mirror of
https://github.com/git/git.git
synced 2026-03-13 10:23:30 +01:00
Merge GIT 1.5.1-rc1
This commit is contained in:
28
Documentation/RelNotes-1.5.0.5.txt
Normal file
28
Documentation/RelNotes-1.5.0.5.txt
Normal file
@@ -0,0 +1,28 @@
|
||||
GIT v1.5.0.5 Release Notes
|
||||
==========================
|
||||
|
||||
Fixes since v1.5.0.3
|
||||
--------------------
|
||||
|
||||
* Bugfixes
|
||||
|
||||
- git-merge (hence git-pull) did not refuse fast-forwarding
|
||||
when the working tree had local changes that would have
|
||||
conflicted with it.
|
||||
|
||||
- git.el does not add duplicate sign-off lines.
|
||||
|
||||
- git-commit shows the full stat of the resulting commit, not
|
||||
just about the files in the current directory, when run from
|
||||
a subdirectory.
|
||||
|
||||
- "git-checkout -m '@{8 hours ago}'" had a funny failure from
|
||||
eval; fixed.
|
||||
|
||||
- git-gui updates.
|
||||
|
||||
* Documentation updates
|
||||
|
||||
* User manual updates
|
||||
|
||||
|
||||
@@ -25,6 +25,21 @@ Updates since v1.5.0
|
||||
- "git diff --pretty=format:<string>" to allow more flexible
|
||||
custom log output.
|
||||
|
||||
- "git diff --no-index" can read from '-' (standard input).
|
||||
|
||||
- "git diff" also learned --exit-code to exit with non-zero
|
||||
status when it found differences. In the future we might
|
||||
want to make this the default but that would be a rather big
|
||||
backward incompatible change; it will stay as an option for
|
||||
now.
|
||||
|
||||
- "git branch --track" can be used to set up configuration
|
||||
variables to help it easier to base your work on branches
|
||||
you track from a remote site.
|
||||
|
||||
- "git format-patch --attach" now emits attachments. Use
|
||||
--inline to get an inlined multipart/mixed.
|
||||
|
||||
- "git name-rev" learned --refs=<pattern>, to limit the tags
|
||||
used for naming the given revisions only to the ones
|
||||
matching the given pattern.
|
||||
@@ -39,6 +54,9 @@ Updates since v1.5.0
|
||||
- "git bundle" can help sneaker-netting your changes between
|
||||
repositories.
|
||||
|
||||
- "git mergetool" can help 3-way file-level conflict
|
||||
resolution with your favorite graphical merge tools.
|
||||
|
||||
- A new configuration "core.symlinks" can be used to disable
|
||||
symlinks on filesystems that do not support them; they are
|
||||
checked out as regular files instead.
|
||||
@@ -46,6 +64,11 @@ Updates since v1.5.0
|
||||
|
||||
* Updated behaviour of existing commands.
|
||||
|
||||
- "git fsck" does not barf on corrupt loose objects.
|
||||
|
||||
- "git archimport" allows remapping when coming up with git
|
||||
branch names from arch names.
|
||||
|
||||
- git-svn got almost a rewrite.
|
||||
|
||||
- core.autocrlf configuration, when set to 'true', makes git
|
||||
@@ -99,6 +122,25 @@ Updates since v1.5.0
|
||||
- "git fetch" (hence "git clone" and "git pull") are less
|
||||
noisy when the output does not go to tty.
|
||||
|
||||
- "git fetch" between repositories with many refs were slow
|
||||
even when there are not many changes that needed
|
||||
transferring. This has been sped up by partially rewriting
|
||||
the heaviest parts in C.
|
||||
|
||||
- "git mailinfo" which splits an e-mail into a patch and the
|
||||
metainformation was rewritten, thanks to Don Zickus. It
|
||||
handles nested multipart better.
|
||||
|
||||
- send-email learned configurable bcc and chain-reply-to.
|
||||
|
||||
- Using objects from packs is now seriouly optimized by clever
|
||||
use of a cache. This should be most noticeable in git-log
|
||||
family of commands that involve reading many tree objects.
|
||||
In addition, traversing revisions while filtering changes
|
||||
with pathspecs is made faster by terminating the comparison
|
||||
between the trees as early as possible.
|
||||
|
||||
|
||||
* Hooks
|
||||
|
||||
- The sample update hook to show how to send out notification
|
||||
@@ -106,9 +148,15 @@ Updates since v1.5.0
|
||||
the repository. Earlier, it showed new commits that appeared
|
||||
on the branch.
|
||||
|
||||
|
||||
* Others
|
||||
|
||||
- git-revert, git-gc and git-cherry-pick are now built-ins.
|
||||
|
||||
|
||||
--
|
||||
exec >/var/tmp/1
|
||||
O=v1.5.0.3-268-g3ddad98
|
||||
O=v1.5.0.5-446-g5d86501
|
||||
echo O=`git describe master`
|
||||
git shortlog --no-merges $O..master ^maint
|
||||
|
||||
|
||||
@@ -240,6 +240,19 @@ the largest projects. You probably do not need to adjust this value.
|
||||
+
|
||||
Common unit suffixes of 'k', 'm', or 'g' are supported.
|
||||
|
||||
core.deltaBaseCacheLimit::
|
||||
Maximum number of bytes to reserve for caching base objects
|
||||
that multiple deltafied objects reference. By storing the
|
||||
entire decompressed base objects in a cache Git is able
|
||||
to avoid unpacking and decompressing frequently used base
|
||||
objects multiple times.
|
||||
+
|
||||
Default is 16 MiB on all platforms. This should be reasonable
|
||||
for all users/operating systems, except on the largest projects.
|
||||
You probably do not need to adjust this value.
|
||||
+
|
||||
Common unit suffixes of 'k', 'm', or 'g' are supported.
|
||||
|
||||
alias.*::
|
||||
Command aliases for the gitlink:git[1] command wrapper - e.g.
|
||||
after defining "alias.last = cat-file commit HEAD", the invocation
|
||||
@@ -272,6 +285,10 @@ branch.<name>.merge::
|
||||
`git fetch`) to lookup the default branch for merging. Without
|
||||
this option, `git pull` defaults to merge the first refspec fetched.
|
||||
Specify multiple values to get an octopus merge.
|
||||
If you wish to setup `git pull` so that it merges into <name> from
|
||||
another branch in the local repository, you can point
|
||||
branch.<name>.merge to the desired branch, and use the special setting
|
||||
`.` (a period) for branch.<name>.remote.
|
||||
|
||||
color.branch::
|
||||
A boolean to enable/disable color in the output of
|
||||
@@ -456,7 +473,7 @@ merge.summary::
|
||||
merge.tool::
|
||||
Controls which merge resolution program is used by
|
||||
gitlink:git-mergetool[l]. Valid values are: "kdiff3", "tkdiff",
|
||||
"meld", "xxdiff", "emerge"
|
||||
"meld", "xxdiff", "emerge", "vimdiff"
|
||||
|
||||
merge.verbosity::
|
||||
Controls the amount of output shown by the recursive merge
|
||||
|
||||
@@ -159,5 +159,10 @@
|
||||
-w::
|
||||
Shorthand for "--ignore-all-space".
|
||||
|
||||
--exit-code::
|
||||
Make the program exit with codes similar to diff(1).
|
||||
That is, it exits with 1 if there were differences and
|
||||
0 means no differences.
|
||||
|
||||
For more detailed explanation on these common options, see also
|
||||
link:diffcore.html[diffcore documentation].
|
||||
|
||||
@@ -25,7 +25,7 @@ OPTIONS
|
||||
-t or --tool=<tool>::
|
||||
Use the merge resolution program specified by <tool>.
|
||||
Valid merge tools are:
|
||||
kdiff3, tkdiff, meld, xxdiff, and emerge.
|
||||
kdiff3, tkdiff, meld, xxdiff, emerge, and vimdiff.
|
||||
|
||||
If a merge resolution program is not specified, 'git mergetool'
|
||||
will use the configuration variable merge.tool. If the
|
||||
|
||||
@@ -60,7 +60,8 @@ The --cc option must be repeated for each user you want on the cc list.
|
||||
is not set, this will be prompted for.
|
||||
|
||||
--no-signed-off-by-cc::
|
||||
Do not add emails found in Signed-off-by: lines to the cc list.
|
||||
Do not add emails found in Signed-off-by: or Cc: lines to the
|
||||
cc list.
|
||||
|
||||
--quiet::
|
||||
Make git-send-email less verbose. One line per email should be
|
||||
|
||||
@@ -35,7 +35,9 @@ ifdef::stalenotes[]
|
||||
You are reading the documentation for the latest version of git.
|
||||
Documentation for older releases are available here:
|
||||
|
||||
* link:v1.5.0.3/git.html[documentation for release 1.5.0.3]
|
||||
* link:v1.5.0.5/git.html[documentation for release 1.5.0.5]
|
||||
|
||||
* link:v1.5.0.5/RelNotes-1.5.0.5.txt[release notes for 1.5.0.5]
|
||||
|
||||
* link:v1.5.0.3/RelNotes-1.5.0.3.txt[release notes for 1.5.0.3]
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#!/bin/sh
|
||||
|
||||
GVF=GIT-VERSION-FILE
|
||||
DEF_VER=v1.5.0.GIT
|
||||
DEF_VER=v1.5.1-rc1.GIT
|
||||
|
||||
LF='
|
||||
'
|
||||
|
||||
3
Makefile
3
Makefile
@@ -177,7 +177,7 @@ BASIC_LDFLAGS =
|
||||
SCRIPT_SH = \
|
||||
git-bisect.sh git-checkout.sh \
|
||||
git-clean.sh git-clone.sh git-commit.sh \
|
||||
git-fetch.sh git-gc.sh \
|
||||
git-fetch.sh \
|
||||
git-ls-remote.sh \
|
||||
git-merge-one-file.sh git-mergetool.sh git-parse-remote.sh \
|
||||
git-pull.sh git-rebase.sh \
|
||||
@@ -297,6 +297,7 @@ BUILTIN_OBJS = \
|
||||
builtin-fmt-merge-msg.o \
|
||||
builtin-for-each-ref.o \
|
||||
builtin-fsck.o \
|
||||
builtin-gc.o \
|
||||
builtin-grep.o \
|
||||
builtin-init-db.o \
|
||||
builtin-log.o \
|
||||
|
||||
@@ -372,9 +372,26 @@ static int get_remote_config(const char *key, const char *value)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void set_branch_defaults(const char *name, const char *real_ref)
|
||||
static void set_branch_merge(const char *name, const char *config_remote,
|
||||
const char *config_repo)
|
||||
{
|
||||
char key[1024];
|
||||
if (sizeof(key) <=
|
||||
snprintf(key, sizeof(key), "branch.%s.remote", name))
|
||||
die("what a long branch name you have!");
|
||||
git_config_set(key, config_remote);
|
||||
|
||||
/*
|
||||
* We do not have to check if we have enough space for
|
||||
* the 'merge' key, since it's shorter than the
|
||||
* previous 'remote' key, which we already checked.
|
||||
*/
|
||||
snprintf(key, sizeof(key), "branch.%s.merge", name);
|
||||
git_config_set(key, config_repo);
|
||||
}
|
||||
|
||||
static void set_branch_defaults(const char *name, const char *real_ref)
|
||||
{
|
||||
const char *slash = strrchr(real_ref, '/');
|
||||
|
||||
if (!slash)
|
||||
@@ -384,21 +401,15 @@ static void set_branch_defaults(const char *name, const char *real_ref)
|
||||
start_len = strlen(real_ref);
|
||||
base_len = slash - real_ref;
|
||||
git_config(get_remote_config);
|
||||
if (!config_repo && !config_remote &&
|
||||
!prefixcmp(real_ref, "refs/heads/")) {
|
||||
set_branch_merge(name, ".", real_ref);
|
||||
printf("Branch %s set up to track local branch %s.\n",
|
||||
name, real_ref);
|
||||
}
|
||||
|
||||
if (config_repo && config_remote) {
|
||||
if (sizeof(key) <=
|
||||
snprintf(key, sizeof(key), "branch.%s.remote", name))
|
||||
die("what a long branch name you have!");
|
||||
git_config_set(key, config_remote);
|
||||
|
||||
/*
|
||||
* We do not have to check if we have enough space for
|
||||
* the 'merge' key, since it's shorter than the
|
||||
* previous 'remote' key, which we already checked.
|
||||
*/
|
||||
snprintf(key, sizeof(key), "branch.%s.merge", name);
|
||||
git_config_set(key, config_repo);
|
||||
|
||||
set_branch_merge(name, config_remote, config_repo);
|
||||
printf("Branch %s set up to track remote branch %s.\n",
|
||||
name, real_ref);
|
||||
}
|
||||
|
||||
129
builtin-bundle.c
129
builtin-bundle.c
@@ -4,7 +4,7 @@
|
||||
#include "diff.h"
|
||||
#include "revision.h"
|
||||
#include "list-objects.h"
|
||||
#include "exec_cmd.h"
|
||||
#include "run-command.h"
|
||||
|
||||
/*
|
||||
* Basic handler for bundle files to connect repositories via sneakernet.
|
||||
@@ -99,67 +99,6 @@ static int read_header(const char *path, struct bundle_header *header) {
|
||||
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 list_refs(struct ref_list *r, int argc, const char **argv)
|
||||
{
|
||||
int i;
|
||||
@@ -263,9 +202,10 @@ static int create_bundle(struct bundle_header *header, const char *path,
|
||||
int bundle_fd = -1;
|
||||
const char **argv_boundary = xmalloc((argc + 4) * sizeof(const char *));
|
||||
const char **argv_pack = xmalloc(5 * sizeof(const char *));
|
||||
int pid, in, out, i, status, ref_count = 0;
|
||||
int i, ref_count = 0;
|
||||
char buffer[1024];
|
||||
struct rev_info revs;
|
||||
struct child_process rls;
|
||||
|
||||
bundle_fd = (!strcmp(path, "-") ? 1 :
|
||||
open(path, O_CREAT | O_EXCL | O_WRONLY, 0666));
|
||||
@@ -285,11 +225,13 @@ static int create_bundle(struct bundle_header *header, const char *path,
|
||||
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)
|
||||
memset(&rls, 0, sizeof(rls));
|
||||
rls.argv = argv_boundary;
|
||||
rls.out = -1;
|
||||
rls.git_cmd = 1;
|
||||
if (start_command(&rls))
|
||||
return -1;
|
||||
while ((i = read_string(out, buffer, sizeof(buffer))) > 0) {
|
||||
while ((i = read_string(rls.out, buffer, sizeof(buffer))) > 0) {
|
||||
unsigned char sha1[20];
|
||||
if (buffer[0] == '-') {
|
||||
write_or_die(bundle_fd, buffer, i);
|
||||
@@ -303,11 +245,8 @@ static int create_bundle(struct bundle_header *header, const char *path,
|
||||
object->flags |= SHOWN;
|
||||
}
|
||||
}
|
||||
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));
|
||||
if (finish_command(&rls))
|
||||
return error("rev-list died");
|
||||
|
||||
/* write references */
|
||||
argc = setup_revisions(argc, argv, &revs, NULL);
|
||||
@@ -352,26 +291,23 @@ static int create_bundle(struct bundle_header *header, const char *path,
|
||||
argv_pack[2] = "--stdout";
|
||||
argv_pack[3] = "--thin";
|
||||
argv_pack[4] = NULL;
|
||||
in = -1;
|
||||
out = bundle_fd;
|
||||
pid = fork_with_pipe(argv_pack, &in, &out);
|
||||
if (pid < 0)
|
||||
memset(&rls, 0, sizeof(rls));
|
||||
rls.argv = argv_pack;
|
||||
rls.in = -1;
|
||||
rls.out = bundle_fd;
|
||||
rls.git_cmd = 1;
|
||||
if (start_command(&rls))
|
||||
return error("Could not spawn pack-objects");
|
||||
for (i = 0; i < revs.pending.nr; i++) {
|
||||
struct object *object = revs.pending.objects[i].item;
|
||||
if (object->flags & UNINTERESTING)
|
||||
write(in, "^", 1);
|
||||
write(in, sha1_to_hex(object->sha1), 40);
|
||||
write(in, "\n", 1);
|
||||
write(rls.in, "^", 1);
|
||||
write(rls.in, sha1_to_hex(object->sha1), 40);
|
||||
write(rls.in, "\n", 1);
|
||||
}
|
||||
close(in);
|
||||
while (waitpid(pid, &status, 0) < 0)
|
||||
if (errno != EINTR)
|
||||
return -1;
|
||||
if (!WIFEXITED(status) || WEXITSTATUS(status))
|
||||
if (finish_command(&rls))
|
||||
return error ("pack-objects died");
|
||||
|
||||
return status;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int unbundle(struct bundle_header *header, int bundle_fd,
|
||||
@@ -379,22 +315,17 @@ static int unbundle(struct bundle_header *header, int bundle_fd,
|
||||
{
|
||||
const char *argv_index_pack[] = {"index-pack",
|
||||
"--fix-thin", "--stdin", NULL};
|
||||
int pid, status, dev_null;
|
||||
struct child_process ip;
|
||||
|
||||
if (verify_bundle(header, 0))
|
||||
return -1;
|
||||
dev_null = open("/dev/null", O_WRONLY);
|
||||
if (dev_null < 0)
|
||||
return error("Could not open /dev/null");
|
||||
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));
|
||||
memset(&ip, 0, sizeof(ip));
|
||||
ip.argv = argv_index_pack;
|
||||
ip.in = bundle_fd;
|
||||
ip.no_stdout = 1;
|
||||
ip.git_cmd = 1;
|
||||
if (run_command(&ip))
|
||||
return error("index-pack died");
|
||||
return list_heads(header, argc, argv);
|
||||
}
|
||||
|
||||
|
||||
@@ -17,6 +17,7 @@ int cmd_diff_files(int argc, const char **argv, const char *prefix)
|
||||
{
|
||||
struct rev_info rev;
|
||||
int nongit = 0;
|
||||
int result;
|
||||
|
||||
prefix = setup_git_directory_gently(&nongit);
|
||||
init_revisions(&rev, prefix);
|
||||
@@ -29,5 +30,6 @@ int cmd_diff_files(int argc, const char **argv, const char *prefix)
|
||||
argc = setup_revisions(argc, argv, &rev, NULL);
|
||||
if (!rev.diffopt.output_format)
|
||||
rev.diffopt.output_format = DIFF_FORMAT_RAW;
|
||||
return run_diff_files_cmd(&rev, argc, argv);
|
||||
result = run_diff_files_cmd(&rev, argc, argv);
|
||||
return rev.diffopt.exit_with_status ? rev.diffopt.has_changes: result;
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@ int cmd_diff_index(int argc, const char **argv, const char *prefix)
|
||||
struct rev_info rev;
|
||||
int cached = 0;
|
||||
int i;
|
||||
int result;
|
||||
|
||||
init_revisions(&rev, prefix);
|
||||
git_config(git_default_config); /* no "diff" UI options */
|
||||
@@ -42,5 +43,6 @@ int cmd_diff_index(int argc, const char **argv, const char *prefix)
|
||||
perror("read_cache");
|
||||
return -1;
|
||||
}
|
||||
return run_diff_index(&rev, cached);
|
||||
result = run_diff_index(&rev, cached);
|
||||
return rev.diffopt.exit_with_status ? rev.diffopt.has_changes: result;
|
||||
}
|
||||
|
||||
@@ -118,7 +118,8 @@ int cmd_diff_tree(int argc, const char **argv, const char *prefix)
|
||||
}
|
||||
|
||||
if (!read_stdin)
|
||||
return 0;
|
||||
return opt->diffopt.exit_with_status ?
|
||||
opt->diffopt.has_changes: 0;
|
||||
|
||||
if (opt->diffopt.detect_rename)
|
||||
opt->diffopt.setup |= (DIFF_SETUP_USE_SIZE_CACHE |
|
||||
@@ -133,5 +134,5 @@ int cmd_diff_tree(int argc, const char **argv, const char *prefix)
|
||||
else
|
||||
diff_tree_stdin(line);
|
||||
}
|
||||
return 0;
|
||||
return opt->diffopt.exit_with_status ? opt->diffopt.has_changes: 0;
|
||||
}
|
||||
|
||||
@@ -190,6 +190,7 @@ int cmd_diff(int argc, const char **argv, const char *prefix)
|
||||
const char *path = NULL;
|
||||
struct blobinfo blob[2];
|
||||
int nongit = 0;
|
||||
int result = 0;
|
||||
|
||||
/*
|
||||
* We could get N tree-ish in the rev.pending_objects list.
|
||||
@@ -292,17 +293,17 @@ int cmd_diff(int argc, const char **argv, const char *prefix)
|
||||
if (!ents) {
|
||||
switch (blobs) {
|
||||
case 0:
|
||||
return run_diff_files_cmd(&rev, argc, argv);
|
||||
result = run_diff_files_cmd(&rev, argc, argv);
|
||||
break;
|
||||
case 1:
|
||||
if (paths != 1)
|
||||
usage(builtin_diff_usage);
|
||||
return builtin_diff_b_f(&rev, argc, argv, blob, path);
|
||||
result = builtin_diff_b_f(&rev, argc, argv, blob, path);
|
||||
break;
|
||||
case 2:
|
||||
if (paths)
|
||||
usage(builtin_diff_usage);
|
||||
return builtin_diff_blobs(&rev, argc, argv, blob);
|
||||
result = builtin_diff_blobs(&rev, argc, argv, blob);
|
||||
break;
|
||||
default:
|
||||
usage(builtin_diff_usage);
|
||||
@@ -311,19 +312,21 @@ int cmd_diff(int argc, const char **argv, const char *prefix)
|
||||
else if (blobs)
|
||||
usage(builtin_diff_usage);
|
||||
else if (ents == 1)
|
||||
return builtin_diff_index(&rev, argc, argv);
|
||||
result = builtin_diff_index(&rev, argc, argv);
|
||||
else if (ents == 2)
|
||||
return builtin_diff_tree(&rev, argc, argv, ent);
|
||||
result = builtin_diff_tree(&rev, argc, argv, ent);
|
||||
else if ((ents == 3) && (ent[0].item->flags & UNINTERESTING)) {
|
||||
/* diff A...B where there is one sane merge base between
|
||||
* A and B. We have ent[0] == merge-base, ent[1] == A,
|
||||
* and ent[2] == B. Show diff between the base and B.
|
||||
*/
|
||||
ent[1] = ent[2];
|
||||
return builtin_diff_tree(&rev, argc, argv, ent);
|
||||
result = builtin_diff_tree(&rev, argc, argv, ent);
|
||||
}
|
||||
else
|
||||
return builtin_diff_combined(&rev, argc, argv,
|
||||
result = builtin_diff_combined(&rev, argc, argv,
|
||||
ent, ents);
|
||||
usage(builtin_diff_usage);
|
||||
if (rev.diffopt.exit_with_status)
|
||||
result = rev.diffopt.has_changes;
|
||||
return result;
|
||||
}
|
||||
|
||||
78
builtin-gc.c
Normal file
78
builtin-gc.c
Normal file
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
* git gc builtin command
|
||||
*
|
||||
* Cleanup unreachable files and optimize the repository.
|
||||
*
|
||||
* Copyright (c) 2007 James Bowes
|
||||
*
|
||||
* Based on git-gc.sh, which is
|
||||
*
|
||||
* Copyright (c) 2006 Shawn O. Pearce
|
||||
*/
|
||||
|
||||
#include "cache.h"
|
||||
#include "run-command.h"
|
||||
|
||||
#define FAILED_RUN "failed to run %s"
|
||||
|
||||
static const char builtin_gc_usage[] = "git-gc [--prune]";
|
||||
|
||||
static int pack_refs = -1;
|
||||
|
||||
static const char *argv_pack_refs[] = {"pack-refs", "--prune", NULL};
|
||||
static const char *argv_reflog[] = {"reflog", "expire", "--all", NULL};
|
||||
static const char *argv_repack[] = {"repack", "-a", "-d", "-l", NULL};
|
||||
static const char *argv_prune[] = {"prune", NULL};
|
||||
static const char *argv_rerere[] = {"rerere", "gc", NULL};
|
||||
|
||||
static int gc_config(const char *var, const char *value)
|
||||
{
|
||||
if (!strcmp(var, "gc.packrefs")) {
|
||||
if (!strcmp(value, "notbare"))
|
||||
pack_refs = -1;
|
||||
else
|
||||
pack_refs = git_config_bool(var, value);
|
||||
return 0;
|
||||
}
|
||||
return git_default_config(var, value);
|
||||
}
|
||||
|
||||
int cmd_gc(int argc, const char **argv, const char *prefix)
|
||||
{
|
||||
int i;
|
||||
int prune = 0;
|
||||
|
||||
git_config(gc_config);
|
||||
|
||||
if (pack_refs < 0)
|
||||
pack_refs = !is_bare_repository();
|
||||
|
||||
for (i = 1; i < argc; i++) {
|
||||
const char *arg = argv[i];
|
||||
if (!strcmp(arg, "--prune")) {
|
||||
prune = 1;
|
||||
continue;
|
||||
}
|
||||
/* perhaps other parameters later... */
|
||||
break;
|
||||
}
|
||||
if (i != argc)
|
||||
usage(builtin_gc_usage);
|
||||
|
||||
if (pack_refs && run_command_v_opt(argv_pack_refs, RUN_GIT_CMD))
|
||||
return error(FAILED_RUN, argv_pack_refs[0]);
|
||||
|
||||
if (run_command_v_opt(argv_reflog, RUN_GIT_CMD))
|
||||
return error(FAILED_RUN, argv_reflog[0]);
|
||||
|
||||
if (run_command_v_opt(argv_repack, RUN_GIT_CMD))
|
||||
return error(FAILED_RUN, argv_repack[0]);
|
||||
|
||||
if (prune && run_command_v_opt(argv_prune, RUN_GIT_CMD))
|
||||
return error(FAILED_RUN, argv_prune[0]);
|
||||
|
||||
if (run_command_v_opt(argv_rerere, RUN_GIT_CMD))
|
||||
return error(FAILED_RUN, argv_rerere[0]);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -166,11 +166,12 @@ static void prepare_pack_revindex(struct pack_revindex *rix)
|
||||
struct packed_git *p = rix->p;
|
||||
int num_ent = num_packed_objects(p);
|
||||
int i;
|
||||
void *index = p->index_base + 256;
|
||||
const char *index = p->index_data;
|
||||
|
||||
index += 4 * 256;
|
||||
rix->revindex = xmalloc(sizeof(*rix->revindex) * (num_ent + 1));
|
||||
for (i = 0; i < num_ent; i++) {
|
||||
unsigned int hl = *((unsigned int *)((char *) index + 24*i));
|
||||
uint32_t hl = *((uint32_t *)(index + 24 * i));
|
||||
rix->revindex[i].offset = ntohl(hl);
|
||||
rix->revindex[i].nr = i;
|
||||
}
|
||||
@@ -217,11 +218,11 @@ static off_t find_packed_object_size(struct packed_git *p, off_t ofs)
|
||||
return entry[1].offset - ofs;
|
||||
}
|
||||
|
||||
static unsigned char *find_packed_object_name(struct packed_git *p,
|
||||
off_t ofs)
|
||||
static const unsigned char *find_packed_object_name(struct packed_git *p,
|
||||
off_t ofs)
|
||||
{
|
||||
struct revindex_entry *entry = find_packed_object(p, ofs);
|
||||
return (unsigned char *)(p->index_base + 256) + 24 * entry->nr + 4;
|
||||
return ((unsigned char *)p->index_data) + 4 * 256 + 24 * entry->nr + 4;
|
||||
}
|
||||
|
||||
static void *delta_against(void *buf, unsigned long size, struct object_entry *entry)
|
||||
@@ -996,7 +997,8 @@ static void check_object(struct object_entry *entry)
|
||||
* delta.
|
||||
*/
|
||||
if (!no_reuse_delta) {
|
||||
unsigned char c, *base_name;
|
||||
unsigned char c;
|
||||
const unsigned char *base_name;
|
||||
off_t ofs;
|
||||
unsigned long used_0;
|
||||
/* there is at least 20 bytes left in the pack */
|
||||
|
||||
@@ -323,10 +323,10 @@ static int do_push(const char *repo)
|
||||
int dest_refspec_nr = refspec_nr;
|
||||
const char **dest_refspec = refspec;
|
||||
const char *dest = uri[i];
|
||||
const char *sender = "git-send-pack";
|
||||
const char *sender = "send-pack";
|
||||
if (!prefixcmp(dest, "http://") ||
|
||||
!prefixcmp(dest, "https://"))
|
||||
sender = "git-http-push";
|
||||
sender = "http-push";
|
||||
else if (thin)
|
||||
argv[dest_argc++] = "--thin";
|
||||
argv[0] = sender;
|
||||
@@ -336,7 +336,7 @@ static int do_push(const char *repo)
|
||||
argv[dest_argc] = NULL;
|
||||
if (verbose)
|
||||
fprintf(stderr, "Pushing to %s\n", dest);
|
||||
err = run_command_v_opt(argv, 0);
|
||||
err = run_command_v_opt(argv, RUN_GIT_CMD);
|
||||
if (!err)
|
||||
continue;
|
||||
switch (err) {
|
||||
|
||||
@@ -235,8 +235,8 @@ static int revert_or_cherry_pick(int argc, const char **argv)
|
||||
unsigned char head[20];
|
||||
struct commit *base, *next;
|
||||
int i;
|
||||
char *oneline, *encoding, *reencoded_message = NULL;
|
||||
const char *message;
|
||||
char *oneline, *reencoded_message = NULL;
|
||||
const char *message, *encoding;
|
||||
|
||||
git_config(git_default_config);
|
||||
me = action == REVERT ? "revert" : "cherry-pick";
|
||||
|
||||
@@ -37,6 +37,7 @@ extern int cmd_fmt_merge_msg(int argc, const char **argv, const char *prefix);
|
||||
extern int cmd_for_each_ref(int argc, const char **argv, const char *prefix);
|
||||
extern int cmd_format_patch(int argc, const char **argv, const char *prefix);
|
||||
extern int cmd_fsck(int argc, const char **argv, const char *prefix);
|
||||
extern int cmd_gc(int argc, const char **argv, const char *prefix);
|
||||
extern int cmd_get_tar_commit_id(int argc, const char **argv, const char *prefix);
|
||||
extern int cmd_grep(int argc, const char **argv, const char *prefix);
|
||||
extern int cmd_help(int argc, const char **argv, const char *prefix);
|
||||
|
||||
12
cache.h
12
cache.h
@@ -229,6 +229,7 @@ extern const char *apply_default_whitespace;
|
||||
extern int zlib_compression_level;
|
||||
extern size_t packed_git_window_size;
|
||||
extern size_t packed_git_limit;
|
||||
extern size_t delta_base_cache_limit;
|
||||
extern int auto_crlf;
|
||||
|
||||
#define GIT_REPO_VERSION 0
|
||||
@@ -372,10 +373,11 @@ struct pack_window {
|
||||
extern struct packed_git {
|
||||
struct packed_git *next;
|
||||
struct pack_window *windows;
|
||||
uint32_t *index_base;
|
||||
time_t mtime;
|
||||
const void *index_data;
|
||||
off_t index_size;
|
||||
off_t pack_size;
|
||||
time_t mtime;
|
||||
int index_version;
|
||||
int pack_fd;
|
||||
int pack_local;
|
||||
unsigned char sha1[20];
|
||||
@@ -413,7 +415,7 @@ extern int server_supports(const char *feature);
|
||||
|
||||
extern struct packed_git *parse_pack_index(unsigned char *sha1);
|
||||
extern struct packed_git *parse_pack_index_file(const unsigned char *sha1,
|
||||
char *idx_path);
|
||||
const char *idx_path);
|
||||
|
||||
extern void prepare_packed_git(void);
|
||||
extern void reprepare_packed_git(void);
|
||||
@@ -425,7 +427,7 @@ extern struct packed_git *find_sha1_pack(const unsigned char *sha1,
|
||||
extern void pack_report(void);
|
||||
extern unsigned char* use_pack(struct packed_git *, struct pack_window **, off_t, unsigned int *);
|
||||
extern void unuse_pack(struct pack_window **);
|
||||
extern struct packed_git *add_packed_git(char *, int, int);
|
||||
extern struct packed_git *add_packed_git(const char *, int, int);
|
||||
extern uint32_t num_packed_objects(const struct packed_git *p);
|
||||
extern int nth_packed_object_sha1(const struct packed_git *, uint32_t, unsigned char*);
|
||||
extern off_t find_pack_entry_one(const unsigned char *, struct packed_git *);
|
||||
@@ -451,7 +453,7 @@ extern int check_repository_format_version(const char *var, const char *value);
|
||||
extern char git_default_email[MAX_GITNAME];
|
||||
extern char git_default_name[MAX_GITNAME];
|
||||
|
||||
extern char *git_commit_encoding;
|
||||
extern const char *git_commit_encoding;
|
||||
extern const char *git_log_output_encoding;
|
||||
|
||||
extern int copy_fd(int ifd, int ofd);
|
||||
|
||||
9
config.c
9
config.c
@@ -331,6 +331,11 @@ int git_default_config(const char *var, const char *value)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!strcmp(var, "core.deltabasecachelimit")) {
|
||||
delta_base_cache_limit = git_config_int(var, value);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!strcmp(var, "core.autocrlf")) {
|
||||
if (value && !strcasecmp(value, "input")) {
|
||||
auto_crlf = -1;
|
||||
@@ -351,12 +356,12 @@ int git_default_config(const char *var, const char *value)
|
||||
}
|
||||
|
||||
if (!strcmp(var, "i18n.commitencoding")) {
|
||||
git_commit_encoding = strdup(value);
|
||||
git_commit_encoding = xstrdup(value);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!strcmp(var, "i18n.logoutputencoding")) {
|
||||
git_log_output_encoding = strdup(value);
|
||||
git_log_output_encoding = xstrdup(value);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
29
connect.c
29
connect.c
@@ -3,6 +3,7 @@
|
||||
#include "pkt-line.h"
|
||||
#include "quote.h"
|
||||
#include "refs.h"
|
||||
#include "run-command.h"
|
||||
#include "spawn-pipe.h"
|
||||
|
||||
static char *server_capabilities;
|
||||
@@ -615,8 +616,8 @@ static void git_proxy_connect(int fd[2], char *host)
|
||||
{
|
||||
const char *port = STR(DEFAULT_GIT_PORT);
|
||||
char *colon, *end;
|
||||
int pipefd[2][2];
|
||||
pid_t pid;
|
||||
const char *argv[4];
|
||||
struct child_process proxy;
|
||||
|
||||
if (host[0] == '[') {
|
||||
end = strchr(host + 1, ']');
|
||||
@@ -635,18 +636,18 @@ static void git_proxy_connect(int fd[2], char *host)
|
||||
port = colon + 1;
|
||||
}
|
||||
|
||||
if (pipe(pipefd[0]) < 0 || pipe(pipefd[1]) < 0)
|
||||
die("unable to create pipe pair for communication");
|
||||
|
||||
{
|
||||
const char *argv[] = { NULL, host, port, NULL };
|
||||
pid = spawnvpe_pipe(git_proxy_command, argv, environ,
|
||||
pipefd[1], pipefd[0]);
|
||||
}
|
||||
if (pid < 0)
|
||||
die("fork failed");
|
||||
fd[0] = pipefd[0][0];
|
||||
fd[1] = pipefd[1][1];
|
||||
argv[0] = git_proxy_command;
|
||||
argv[1] = host;
|
||||
argv[2] = port;
|
||||
argv[3] = NULL;
|
||||
memset(&proxy, 0, sizeof(proxy));
|
||||
proxy.argv = argv;
|
||||
proxy.in = -1;
|
||||
proxy.out = -1;
|
||||
if (start_command(&proxy))
|
||||
die("cannot start proxy %s", argv[0]);
|
||||
fd[0] = proxy.out; /* read from proxy stdout */
|
||||
fd[1] = proxy.in; /* write to proxy stdin */
|
||||
}
|
||||
|
||||
#define MAX_CMD_LEN 1024
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
;;; git.el --- A user interface for git
|
||||
|
||||
;; Copyright (C) 2005, 2006 Alexandre Julliard <julliard@winehq.org>
|
||||
;; Copyright (C) 2005, 2006, 2007 Alexandre Julliard <julliard@winehq.org>
|
||||
|
||||
;; Version: 1.0
|
||||
|
||||
@@ -213,6 +213,23 @@ and returns the process output as a string."
|
||||
(error "Failed to run \"git %s\":\n%s" (mapconcat (lambda (x) x) args " ") (buffer-string)))
|
||||
(message "Running git %s...done" (car args)))
|
||||
|
||||
(defun git-run-hook (hook env &rest args)
|
||||
"Run a git hook and display its output if any."
|
||||
(let ((dir default-directory)
|
||||
(hook-name (expand-file-name (concat ".git/hooks/" hook))))
|
||||
(or (not (file-executable-p hook-name))
|
||||
(let (status (buffer (get-buffer-create "*Git Hook Output*")))
|
||||
(with-current-buffer buffer
|
||||
(erase-buffer)
|
||||
(cd dir)
|
||||
(setq status
|
||||
(if env
|
||||
(apply #'call-process "env" nil (list buffer t) nil
|
||||
(append (git-get-env-strings env) (list hook-name) args))
|
||||
(apply #'call-process hook-name nil (list buffer t) nil args))))
|
||||
(display-message-or-buffer buffer)
|
||||
(eq 0 status)))))
|
||||
|
||||
(defun git-get-string-sha1 (string)
|
||||
"Read a SHA1 from the specified string."
|
||||
(and string
|
||||
@@ -590,6 +607,20 @@ and returns the process output as a string."
|
||||
(when modified
|
||||
(apply #'git-run-command nil env "update-index" "--" (git-get-filenames modified)))))
|
||||
|
||||
(defun git-run-pre-commit-hook ()
|
||||
"Run the pre-commit hook if any."
|
||||
(unless git-status (error "Not in git-status buffer."))
|
||||
(let ((files (git-marked-files-state 'added 'deleted 'modified)))
|
||||
(or (not files)
|
||||
(not (file-executable-p ".git/hooks/pre-commit"))
|
||||
(let ((index-file (make-temp-file "gitidx")))
|
||||
(unwind-protect
|
||||
(let ((head-tree (unless (git-empty-db-p) (git-rev-parse "HEAD^{tree}"))))
|
||||
(git-read-tree head-tree index-file)
|
||||
(git-update-index index-file files)
|
||||
(git-run-hook "pre-commit" `(("GIT_INDEX_FILE" . ,index-file))))
|
||||
(delete-file index-file))))))
|
||||
|
||||
(defun git-do-commit ()
|
||||
"Perform the actual commit using the current buffer as log message."
|
||||
(interactive)
|
||||
@@ -622,7 +653,8 @@ and returns the process output as a string."
|
||||
(git-run-command nil nil "rerere"))
|
||||
(git-refresh-files)
|
||||
(git-refresh-ewoc-hf git-status)
|
||||
(message "Committed %s." commit))
|
||||
(message "Committed %s." commit)
|
||||
(git-run-hook "post-commit" nil))
|
||||
(message "Commit aborted."))))
|
||||
(message "No files to commit.")))
|
||||
(delete-file index-file))))))
|
||||
@@ -944,28 +976,29 @@ and returns the process output as a string."
|
||||
"Commit the marked file(s), asking for a commit message."
|
||||
(interactive)
|
||||
(unless git-status (error "Not in git-status buffer."))
|
||||
(let ((buffer (get-buffer-create "*git-commit*"))
|
||||
(coding-system (git-get-commits-coding-system))
|
||||
author-name author-email subject date)
|
||||
(when (eq 0 (buffer-size buffer))
|
||||
(when (file-readable-p ".dotest/info")
|
||||
(with-temp-buffer
|
||||
(insert-file-contents ".dotest/info")
|
||||
(goto-char (point-min))
|
||||
(when (re-search-forward "^Author: \\(.*\\)\nEmail: \\(.*\\)$" nil t)
|
||||
(setq author-name (match-string 1))
|
||||
(setq author-email (match-string 2)))
|
||||
(goto-char (point-min))
|
||||
(when (re-search-forward "^Subject: \\(.*\\)$" nil t)
|
||||
(setq subject (match-string 1)))
|
||||
(goto-char (point-min))
|
||||
(when (re-search-forward "^Date: \\(.*\\)$" nil t)
|
||||
(setq date (match-string 1)))))
|
||||
(git-setup-log-buffer buffer author-name author-email subject date))
|
||||
(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)))
|
||||
(when (git-run-pre-commit-hook)
|
||||
(let ((buffer (get-buffer-create "*git-commit*"))
|
||||
(coding-system (git-get-commits-coding-system))
|
||||
author-name author-email subject date)
|
||||
(when (eq 0 (buffer-size buffer))
|
||||
(when (file-readable-p ".dotest/info")
|
||||
(with-temp-buffer
|
||||
(insert-file-contents ".dotest/info")
|
||||
(goto-char (point-min))
|
||||
(when (re-search-forward "^Author: \\(.*\\)\nEmail: \\(.*\\)$" nil t)
|
||||
(setq author-name (match-string 1))
|
||||
(setq author-email (match-string 2)))
|
||||
(goto-char (point-min))
|
||||
(when (re-search-forward "^Subject: \\(.*\\)$" nil t)
|
||||
(setq subject (match-string 1)))
|
||||
(goto-char (point-min))
|
||||
(when (re-search-forward "^Date: \\(.*\\)$" nil t)
|
||||
(setq date (match-string 1)))))
|
||||
(git-setup-log-buffer buffer author-name author-email subject date))
|
||||
(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 ()
|
||||
"Visit the current file in its own buffer."
|
||||
|
||||
11
diff-lib.c
11
diff-lib.c
@@ -170,8 +170,10 @@ static int handle_diff_files_args(struct rev_info *revs,
|
||||
else if (!strcmp(argv[1], "--theirs"))
|
||||
revs->max_count = 3;
|
||||
else if (!strcmp(argv[1], "-n") ||
|
||||
!strcmp(argv[1], "--no-index"))
|
||||
!strcmp(argv[1], "--no-index")) {
|
||||
revs->max_count = -2;
|
||||
revs->diffopt.exit_with_status = 1;
|
||||
}
|
||||
else if (!strcmp(argv[1], "-q"))
|
||||
*silent = 1;
|
||||
else
|
||||
@@ -237,6 +239,7 @@ int setup_diff_no_index(struct rev_info *revs,
|
||||
break;
|
||||
} else if (i < argc - 3 && !strcmp(argv[i], "--no-index")) {
|
||||
i = argc - 3;
|
||||
revs->diffopt.exit_with_status = 1;
|
||||
break;
|
||||
}
|
||||
if (argc != i + 2 || (!is_outside_repo(argv[i + 1], nongit, prefix) &&
|
||||
@@ -321,6 +324,9 @@ int run_diff_files(struct rev_info *revs, int silent_on_removed)
|
||||
struct cache_entry *ce = active_cache[i];
|
||||
int changed;
|
||||
|
||||
if (revs->diffopt.quiet && revs->diffopt.has_changes)
|
||||
break;
|
||||
|
||||
if (!ce_path_match(ce, revs->prune_data))
|
||||
continue;
|
||||
|
||||
@@ -562,6 +568,9 @@ static int diff_cache(struct rev_info *revs,
|
||||
struct cache_entry *ce = *ac;
|
||||
int same = (entries > 1) && ce_same_name(ce, ac[1]);
|
||||
|
||||
if (revs->diffopt.quiet && revs->diffopt.has_changes)
|
||||
break;
|
||||
|
||||
if (!ce_path_match(ce, pathspec))
|
||||
goto skip_entry;
|
||||
|
||||
|
||||
36
diff.c
36
diff.c
@@ -1953,6 +1953,23 @@ int diff_setup_done(struct diff_options *options)
|
||||
if (options->abbrev <= 0 || 40 < options->abbrev)
|
||||
options->abbrev = 40; /* full */
|
||||
|
||||
/*
|
||||
* It does not make sense to show the first hit we happened
|
||||
* to have found. It does not make sense not to return with
|
||||
* exit code in such a case either.
|
||||
*/
|
||||
if (options->quiet) {
|
||||
options->output_format = DIFF_FORMAT_NO_OUTPUT;
|
||||
options->exit_with_status = 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* If we postprocess in diffcore, we cannot simply return
|
||||
* upon the first hit. We need to run diff as usual.
|
||||
*/
|
||||
if (options->pickaxe || options->filter)
|
||||
options->quiet = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -2129,6 +2146,10 @@ int diff_opt_parse(struct diff_options *options, const char **av, int ac)
|
||||
options->color_diff = options->color_diff_words = 1;
|
||||
else if (!strcmp(arg, "--no-renames"))
|
||||
options->detect_rename = 0;
|
||||
else if (!strcmp(arg, "--exit-code"))
|
||||
options->exit_with_status = 1;
|
||||
else if (!strcmp(arg, "--quiet"))
|
||||
options->quiet = 1;
|
||||
else
|
||||
return 0;
|
||||
return 1;
|
||||
@@ -2893,6 +2914,8 @@ static void diffcore_apply_filter(const char *filter)
|
||||
|
||||
void diffcore_std(struct diff_options *options)
|
||||
{
|
||||
if (options->quiet)
|
||||
return;
|
||||
if (options->break_opt != -1)
|
||||
diffcore_break(options->break_opt);
|
||||
if (options->detect_rename)
|
||||
@@ -2905,18 +2928,11 @@ void diffcore_std(struct diff_options *options)
|
||||
diffcore_order(options->orderfile);
|
||||
diff_resolve_rename_copy();
|
||||
diffcore_apply_filter(options->filter);
|
||||
|
||||
options->has_changes = !!diff_queued_diff.nr;
|
||||
}
|
||||
|
||||
|
||||
void diffcore_std_no_resolve(struct diff_options *options)
|
||||
{
|
||||
if (options->pickaxe)
|
||||
diffcore_pickaxe(options->pickaxe, options->pickaxe_opts);
|
||||
if (options->orderfile)
|
||||
diffcore_order(options->orderfile);
|
||||
diffcore_apply_filter(options->filter);
|
||||
}
|
||||
|
||||
void diff_addremove(struct diff_options *options,
|
||||
int addremove, unsigned mode,
|
||||
const unsigned char *sha1,
|
||||
@@ -2952,6 +2968,7 @@ void diff_addremove(struct diff_options *options,
|
||||
fill_filespec(two, sha1, mode);
|
||||
|
||||
diff_queue(&diff_queued_diff, one, two);
|
||||
options->has_changes = 1;
|
||||
}
|
||||
|
||||
void diff_change(struct diff_options *options,
|
||||
@@ -2977,6 +2994,7 @@ void diff_change(struct diff_options *options,
|
||||
fill_filespec(two, new_sha1, new_mode);
|
||||
|
||||
diff_queue(&diff_queued_diff, one, two);
|
||||
options->has_changes = 1;
|
||||
}
|
||||
|
||||
void diff_unmerge(struct diff_options *options,
|
||||
|
||||
7
diff.h
7
diff.h
@@ -56,7 +56,10 @@ struct diff_options {
|
||||
silent_on_remove:1,
|
||||
find_copies_harder:1,
|
||||
color_diff:1,
|
||||
color_diff_words:1;
|
||||
color_diff_words:1,
|
||||
has_changes:1,
|
||||
quiet:1,
|
||||
exit_with_status:1;
|
||||
int context;
|
||||
int break_opt;
|
||||
int detect_rename;
|
||||
@@ -170,8 +173,6 @@ extern int diff_setup_done(struct diff_options *);
|
||||
|
||||
extern void diffcore_std(struct diff_options *);
|
||||
|
||||
extern void diffcore_std_no_resolve(struct diff_options *);
|
||||
|
||||
#define COMMON_DIFF_OPTIONS_HELP \
|
||||
"\ncommon diff options:\n" \
|
||||
" -z output diff-raw with lines terminated with NUL.\n" \
|
||||
|
||||
@@ -20,13 +20,14 @@ int is_bare_repository_cfg = -1; /* unspecified */
|
||||
int log_all_ref_updates = -1; /* unspecified */
|
||||
int warn_ambiguous_refs = 1;
|
||||
int repository_format_version;
|
||||
char *git_commit_encoding;
|
||||
const char *git_commit_encoding;
|
||||
const char *git_log_output_encoding;
|
||||
int shared_repository = PERM_UMASK;
|
||||
const char *apply_default_whitespace;
|
||||
int zlib_compression_level = Z_DEFAULT_COMPRESSION;
|
||||
size_t packed_git_window_size = DEFAULT_PACKED_GIT_WINDOW_SIZE;
|
||||
size_t packed_git_limit = DEFAULT_PACKED_GIT_LIMIT;
|
||||
size_t delta_base_cache_limit = 16 * 1024 * 1024;
|
||||
int pager_in_use;
|
||||
int pager_use_color = 1;
|
||||
int auto_crlf = 0; /* 1: both ways, -1: only when adding git objects */
|
||||
|
||||
@@ -77,9 +77,9 @@ do
|
||||
*)
|
||||
git-mailinfo $keep_subject $utf8 \
|
||||
.dotest/msg .dotest/patch <$i >.dotest/info || exit 1
|
||||
test -s $dotest/patch || {
|
||||
test -s .dotest/patch || {
|
||||
echo "Patch is empty. Was is split wrong?"
|
||||
stop_here $this
|
||||
exit 1
|
||||
}
|
||||
git-stripspace < .dotest/msg > .dotest/msg-clean
|
||||
;;
|
||||
|
||||
@@ -89,7 +89,7 @@ while [ "$#" != "0" ]; do
|
||||
esac
|
||||
done
|
||||
|
||||
case "$new_branch,$track" in
|
||||
case "$newbranch,$track" in
|
||||
,--*)
|
||||
die "git checkout: --track and --no-track require -b"
|
||||
esac
|
||||
|
||||
@@ -947,6 +947,7 @@ sub req_update
|
||||
|
||||
# we need to merge with the local changes ( M=successful merge, C=conflict merge )
|
||||
$log->info("Merging $file_local, $file_old, $file_new");
|
||||
print "M Merging differences between 1.$oldmeta->{revision} and 1.$meta->{revision} into $filename\n";
|
||||
|
||||
$log->debug("Temporary directory for merge is $dir");
|
||||
|
||||
@@ -973,6 +974,7 @@ sub req_update
|
||||
elsif ( $return == 1 )
|
||||
{
|
||||
$log->info("Merged with conflicts");
|
||||
print "E cvs update: conflicts found in $filename\n";
|
||||
print "M C $filename\n";
|
||||
|
||||
# Don't want to actually _DO_ the update if -n specified
|
||||
@@ -1067,6 +1069,7 @@ sub req_ci
|
||||
$log->info("Created index '$file_index' with for head $state->{module} - exit status $?");
|
||||
|
||||
my @committedfiles = ();
|
||||
my %oldmeta;
|
||||
|
||||
# foreach file specified on the command line ...
|
||||
foreach my $filename ( @{$state->{args}} )
|
||||
@@ -1077,6 +1080,7 @@ sub req_ci
|
||||
next unless ( exists $state->{entries}{$filename}{modified_filename} or not $state->{entries}{$filename}{unchanged} );
|
||||
|
||||
my $meta = $updater->getmeta($filename);
|
||||
$oldmeta{$filename} = $meta;
|
||||
|
||||
my $wrev = revparse($filename);
|
||||
|
||||
@@ -1205,11 +1209,18 @@ sub req_ci
|
||||
|
||||
$log->debug("Checked-in $dirpart : $filename");
|
||||
|
||||
print "M $state->{CVSROOT}/$state->{module}/$filename,v <-- $dirpart$filepart\n";
|
||||
if ( defined $meta->{filehash} && $meta->{filehash} eq "deleted" )
|
||||
{
|
||||
print "M new revision: delete; previous revision: 1.$oldmeta{$filename}{revision}\n";
|
||||
print "Remove-entry $dirpart\n";
|
||||
print "$filename\n";
|
||||
} else {
|
||||
if ($meta->{revision} == 1) {
|
||||
print "M initial revision: 1.1\n";
|
||||
} else {
|
||||
print "M new revision: 1.$meta->{revision}; previous revision: 1.$oldmeta{$filename}{revision}\n";
|
||||
}
|
||||
print "Checked-in $dirpart\n";
|
||||
print "$filename\n";
|
||||
my $kopts = kopts_from_path($filepart);
|
||||
@@ -1295,7 +1306,7 @@ sub req_status
|
||||
}
|
||||
if ( defined($meta->{revision}) )
|
||||
{
|
||||
print "M Repository revision:\t1." . $meta->{revision} . "\t$state->{repository}/$filename,v\n";
|
||||
print "M Repository revision:\t1." . $meta->{revision} . "\t$state->{CVSROOT}/$state->{module}/$filename,v\n";
|
||||
print "M Sticky Tag:\t\t(none)\n";
|
||||
print "M Sticky Date:\t\t(none)\n";
|
||||
print "M Sticky Options:\t\t(none)\n";
|
||||
|
||||
12
git-fetch.sh
12
git-fetch.sh
@@ -157,7 +157,7 @@ then
|
||||
fi
|
||||
fi
|
||||
|
||||
fetch_native () {
|
||||
fetch_all_at_once () {
|
||||
|
||||
eval=$(echo "$1" | git-fetch--tool parse-reflist "-")
|
||||
eval "$eval"
|
||||
@@ -165,7 +165,9 @@ fetch_native () {
|
||||
( : subshell because we muck with IFS
|
||||
IFS=" $LF"
|
||||
(
|
||||
if test -f "$remote" ; then
|
||||
if test "$remote" = . ; then
|
||||
git-show-ref $rref || echo failed "$remote"
|
||||
elif test -f "$remote" ; then
|
||||
test -n "$shallow_depth" &&
|
||||
die "shallow clone with bundle is not supported"
|
||||
git-bundle unbundle "$remote" $rref ||
|
||||
@@ -188,7 +190,7 @@ fetch_native () {
|
||||
|
||||
}
|
||||
|
||||
fetch_dumb () {
|
||||
fetch_per_ref () {
|
||||
reflist="$1"
|
||||
refs=
|
||||
rref=
|
||||
@@ -292,10 +294,10 @@ fetch_dumb () {
|
||||
fetch_main () {
|
||||
case "$remote" in
|
||||
http://* | https://* | ftp://* | rsync://* )
|
||||
fetch_dumb "$@"
|
||||
fetch_per_ref "$@"
|
||||
;;
|
||||
*)
|
||||
fetch_native "$@"
|
||||
fetch_all_at_once "$@"
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
4
git-merge.sh
Normal file → Executable file
4
git-merge.sh
Normal file → Executable file
@@ -337,13 +337,13 @@ f,*)
|
||||
# Again the most common case of merging one remote.
|
||||
echo "Updating $(git-rev-parse --short $head)..$(git-rev-parse --short $1)"
|
||||
git-update-index --refresh 2>/dev/null
|
||||
new_head=$(git-rev-parse --verify "$1^0") &&
|
||||
merge_local_changes $head $new_head &&
|
||||
msg="Fast forward"
|
||||
if test -n "$have_message"
|
||||
then
|
||||
msg="$msg (no commit created; -m option ignored)"
|
||||
fi
|
||||
new_head=$(git-rev-parse --verify "$1^0") &&
|
||||
merge_local_changes $head $new_head &&
|
||||
finish "$new_head" "$msg" || exit
|
||||
dropsave
|
||||
exit 0
|
||||
|
||||
@@ -185,9 +185,9 @@ merge_file () {
|
||||
mv -- "$BACKUP" "$path.orig"
|
||||
fi
|
||||
;;
|
||||
meld)
|
||||
meld|vimdiff)
|
||||
touch "$BACKUP"
|
||||
meld -- "$LOCAL" "$path" "$REMOTE"
|
||||
$merge_tool -- "$LOCAL" "$path" "$REMOTE"
|
||||
if test "$path" -nt "$BACKUP" ; then
|
||||
status=0;
|
||||
else
|
||||
@@ -288,10 +288,15 @@ done
|
||||
|
||||
if test -z "$merge_tool"; then
|
||||
merge_tool=`git-config merge.tool`
|
||||
if test $merge_tool = kdiff3 -o $merge_tool = tkdiff -o \
|
||||
$merge_tool = xxdiff -o $merge_tool = meld ; then
|
||||
unset merge_tool
|
||||
fi
|
||||
case "$merge_tool" in
|
||||
kdiff3 | tkdiff | xxdiff | meld | emerge | vimdiff)
|
||||
;; # happy
|
||||
*)
|
||||
echo >&2 "git config option merge.tool set to unknown tool: $merge_tool"
|
||||
echo >&2 "Resetting to default..."
|
||||
unset merge_tool
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
|
||||
if test -z "$merge_tool" ; then
|
||||
@@ -305,6 +310,8 @@ if test -z "$merge_tool" ; then
|
||||
merge_tool=meld
|
||||
elif type emacs >/dev/null 2>&1; then
|
||||
merge_tool=emerge
|
||||
elif type vimdiff >/dev/null 2>&1; then
|
||||
merge_tool=vimdiff
|
||||
else
|
||||
echo "No available merge resolution programs available."
|
||||
exit 1
|
||||
@@ -312,7 +319,7 @@ if test -z "$merge_tool" ; then
|
||||
fi
|
||||
|
||||
case "$merge_tool" in
|
||||
kdiff3|tkdiff|meld|xxdiff)
|
||||
kdiff3|tkdiff|meld|xxdiff|vimdiff)
|
||||
if ! type "$merge_tool" > /dev/null 2>&1; then
|
||||
echo "The merge tool $merge_tool is not available"
|
||||
exit 1
|
||||
|
||||
@@ -9,6 +9,9 @@ get_data_source () {
|
||||
*/*)
|
||||
echo ''
|
||||
;;
|
||||
.)
|
||||
echo self
|
||||
;;
|
||||
*)
|
||||
if test "$(git-config --get "remote.$1.url")"
|
||||
then
|
||||
@@ -31,6 +34,9 @@ get_remote_url () {
|
||||
'')
|
||||
echo "$1"
|
||||
;;
|
||||
self)
|
||||
echo "$1"
|
||||
;;
|
||||
config)
|
||||
git-config --get "remote.$1.url"
|
||||
;;
|
||||
@@ -57,7 +63,7 @@ get_default_remote () {
|
||||
get_remote_default_refs_for_push () {
|
||||
data_source=$(get_data_source "$1")
|
||||
case "$data_source" in
|
||||
'' | branches)
|
||||
'' | branches | self)
|
||||
;; # no default push mapping, just send matching refs.
|
||||
config)
|
||||
git-config --get-all "remote.$1.push" ;;
|
||||
@@ -163,6 +169,10 @@ get_remote_default_refs_for_fetch () {
|
||||
case "$data_source" in
|
||||
'')
|
||||
echo "HEAD:" ;;
|
||||
self)
|
||||
canon_refs_list_for_fetch -d "$1" \
|
||||
$(git-for-each-ref --format='%(refname):')
|
||||
;;
|
||||
config)
|
||||
canon_refs_list_for_fetch -d "$1" \
|
||||
$(git-config --get-all "remote.$1.fetch") ;;
|
||||
@@ -177,7 +187,7 @@ get_remote_default_refs_for_fetch () {
|
||||
}' "$GIT_DIR/remotes/$1")
|
||||
;;
|
||||
*)
|
||||
die "internal error: get-remote-default-ref-for-push $1" ;;
|
||||
die "internal error: get-remote-default-ref-for-fetch $1" ;;
|
||||
esac
|
||||
}
|
||||
|
||||
|
||||
@@ -65,8 +65,8 @@ Options:
|
||||
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.
|
||||
that appear in Signed-off-by: or Cc: lines 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.
|
||||
@@ -572,8 +572,8 @@ foreach my $t (@files) {
|
||||
}
|
||||
} else {
|
||||
$message .= $_;
|
||||
if (/^Signed-off-by: (.*)$/i && !$no_signed_off_cc) {
|
||||
my $c = $1;
|
||||
if (/^(Signed-off-by|Cc): (.*)$/i && !$no_signed_off_cc) {
|
||||
my $c = $2;
|
||||
chomp $c;
|
||||
push @cc, $c;
|
||||
printf("(sob) Adding cc: %s from line '%s'\n",
|
||||
|
||||
1
git.c
1
git.c
@@ -253,6 +253,7 @@ static void handle_internal_command(int argc, const char **argv, char **envp)
|
||||
{ "format-patch", cmd_format_patch, RUN_SETUP },
|
||||
{ "fsck", cmd_fsck, RUN_SETUP },
|
||||
{ "fsck-objects", cmd_fsck, RUN_SETUP },
|
||||
{ "gc", cmd_gc, RUN_SETUP },
|
||||
{ "get-tar-commit-id", cmd_get_tar_commit_id },
|
||||
{ "grep", cmd_grep, RUN_SETUP | USE_PAGER },
|
||||
{ "help", cmd_help },
|
||||
|
||||
@@ -64,9 +64,9 @@ static int copy_file(const char *source, char *dest, const char *hex,
|
||||
}
|
||||
/* If we got ENOENT there is no point continuing. */
|
||||
if (errno == ENOENT) {
|
||||
if (warn_if_not_exists)
|
||||
fprintf(stderr, "does not exist %s\n", source);
|
||||
return -1;
|
||||
if (!warn_if_not_exists)
|
||||
return -1;
|
||||
return error("does not exist %s", source);
|
||||
}
|
||||
}
|
||||
if (use_symlink) {
|
||||
@@ -74,9 +74,8 @@ static int copy_file(const char *source, char *dest, const char *hex,
|
||||
if (stat(source, &st)) {
|
||||
if (!warn_if_not_exists && errno == ENOENT)
|
||||
return -1;
|
||||
fprintf(stderr, "cannot stat %s: %s\n", source,
|
||||
strerror(errno));
|
||||
return -1;
|
||||
return error("cannot stat %s: %s", source,
|
||||
strerror(errno));
|
||||
}
|
||||
if (!symlink(source, dest)) {
|
||||
pull_say("symlink %s\n", hex);
|
||||
@@ -90,25 +89,21 @@ static int copy_file(const char *source, char *dest, const char *hex,
|
||||
if (ifd < 0) {
|
||||
if (!warn_if_not_exists && errno == ENOENT)
|
||||
return -1;
|
||||
fprintf(stderr, "cannot open %s\n", source);
|
||||
return -1;
|
||||
return error("cannot open %s", source);
|
||||
}
|
||||
ofd = open(dest, O_WRONLY | O_CREAT | O_EXCL, 0666);
|
||||
if (ofd < 0) {
|
||||
fprintf(stderr, "cannot open %s\n", dest);
|
||||
close(ifd);
|
||||
return -1;
|
||||
return error("cannot open %s", dest);
|
||||
}
|
||||
status = copy_fd(ifd, ofd);
|
||||
close(ofd);
|
||||
if (status)
|
||||
fprintf(stderr, "cannot write %s\n", dest);
|
||||
else
|
||||
pull_say("copy %s\n", hex);
|
||||
return status;
|
||||
return error("cannot write %s", dest);
|
||||
pull_say("copy %s\n", hex);
|
||||
return 0;
|
||||
}
|
||||
fprintf(stderr, "failed to copy %s with given copy methods.\n", hex);
|
||||
return -1;
|
||||
return error("failed to copy %s with given copy methods.", hex);
|
||||
}
|
||||
|
||||
static int fetch_pack(const unsigned char *sha1)
|
||||
@@ -181,13 +176,11 @@ int fetch_ref(char *ref, unsigned char *sha1)
|
||||
ifd = open(filename, O_RDONLY);
|
||||
if (ifd < 0) {
|
||||
close(ifd);
|
||||
fprintf(stderr, "cannot open %s\n", filename);
|
||||
return -1;
|
||||
return error("cannot open %s", filename);
|
||||
}
|
||||
if (read_in_full(ifd, hex, 40) != 40 || get_sha1_hex(hex, sha1)) {
|
||||
close(ifd);
|
||||
fprintf(stderr, "cannot read from %s\n", filename);
|
||||
return -1;
|
||||
return error("cannot read from %s", filename);
|
||||
}
|
||||
close(ifd);
|
||||
pull_say("ref %s\n", sha1_to_hex(sha1));
|
||||
|
||||
@@ -1,20 +1,17 @@
|
||||
#include "cache.h"
|
||||
#include "spawn-pipe.h"
|
||||
#include "run-command.h"
|
||||
|
||||
static const char *pgm;
|
||||
static const char *arguments[9]; /* last one is always NULL */
|
||||
static const char *arguments[9];
|
||||
static int one_shot, quiet;
|
||||
static int err;
|
||||
|
||||
static void run_program(void)
|
||||
{
|
||||
pid_t pid = spawnvpe_pipe(pgm, arguments, environ, NULL, NULL);
|
||||
int status;
|
||||
|
||||
if (pid < 0)
|
||||
die("unable to fork");
|
||||
|
||||
if (waitpid(pid, &status, 0) < 0 || !WIFEXITED(status) || WEXITSTATUS(status)) {
|
||||
struct child_process child;
|
||||
memset(&child, 0, sizeof(child));
|
||||
child.argv = arguments;
|
||||
if (run_command(&child)) {
|
||||
if (one_shot) {
|
||||
err++;
|
||||
} else {
|
||||
@@ -31,6 +28,7 @@ static int merge_entry(int pos, const char *path)
|
||||
|
||||
if (pos >= active_nr)
|
||||
die("git-merge-index: %s not in the cache", path);
|
||||
arguments[0] = pgm;
|
||||
arguments[1] = "";
|
||||
arguments[2] = "";
|
||||
arguments[3] = "";
|
||||
@@ -38,6 +36,7 @@ static int merge_entry(int pos, const char *path)
|
||||
arguments[5] = "";
|
||||
arguments[6] = "";
|
||||
arguments[7] = "";
|
||||
arguments[8] = NULL;
|
||||
found = 0;
|
||||
do {
|
||||
static char hexbuf[4][60];
|
||||
|
||||
@@ -5,7 +5,7 @@ static int verify_packfile(struct packed_git *p,
|
||||
struct pack_window **w_curs)
|
||||
{
|
||||
off_t index_size = p->index_size;
|
||||
void *index_base = p->index_base;
|
||||
const unsigned char *index_base = p->index_data;
|
||||
SHA_CTX ctx;
|
||||
unsigned char sha1[20];
|
||||
off_t offset = 0, pack_sig = p->pack_size - 20;
|
||||
@@ -31,7 +31,7 @@ static int verify_packfile(struct packed_git *p,
|
||||
if (hashcmp(sha1, use_pack(p, w_curs, pack_sig, NULL)))
|
||||
return error("Packfile %s SHA1 mismatch with itself",
|
||||
p->pack_name);
|
||||
if (hashcmp(sha1, (unsigned char *)index_base + index_size - 40))
|
||||
if (hashcmp(sha1, index_base + index_size - 40))
|
||||
return error("Packfile %s SHA1 mismatch with idx",
|
||||
p->pack_name);
|
||||
unuse_pack(w_curs);
|
||||
@@ -127,7 +127,7 @@ static void show_pack_info(struct packed_git *p)
|
||||
int verify_pack(struct packed_git *p, int verbose)
|
||||
{
|
||||
off_t index_size = p->index_size;
|
||||
void *index_base = p->index_base;
|
||||
const unsigned char *index_base = p->index_data;
|
||||
SHA_CTX ctx;
|
||||
unsigned char sha1[20];
|
||||
int ret;
|
||||
@@ -137,7 +137,7 @@ int verify_pack(struct packed_git *p, int verbose)
|
||||
SHA1_Init(&ctx);
|
||||
SHA1_Update(&ctx, index_base, (unsigned int)(index_size - 20));
|
||||
SHA1_Final(sha1, &ctx);
|
||||
if (hashcmp(sha1, (unsigned char *)index_base + index_size - 20))
|
||||
if (hashcmp(sha1, index_base + index_size - 20))
|
||||
ret = error("Packfile index for %s SHA1 mismatch",
|
||||
p->pack_name);
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@ static int load_all_packs, verbose, alt_odb;
|
||||
|
||||
struct llist_item {
|
||||
struct llist_item *next;
|
||||
unsigned char *sha1;
|
||||
const unsigned char *sha1;
|
||||
};
|
||||
static struct llist {
|
||||
struct llist_item *front;
|
||||
@@ -104,9 +104,9 @@ static struct llist * llist_copy(struct llist *list)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline struct llist_item * llist_insert(struct llist *list,
|
||||
struct llist_item *after,
|
||||
unsigned char *sha1)
|
||||
static inline struct llist_item *llist_insert(struct llist *list,
|
||||
struct llist_item *after,
|
||||
const unsigned char *sha1)
|
||||
{
|
||||
struct llist_item *new = llist_item_get();
|
||||
new->sha1 = sha1;
|
||||
@@ -128,12 +128,14 @@ static inline struct llist_item * llist_insert(struct llist *list,
|
||||
return new;
|
||||
}
|
||||
|
||||
static inline struct llist_item *llist_insert_back(struct llist *list, unsigned char *sha1)
|
||||
static inline struct llist_item *llist_insert_back(struct llist *list,
|
||||
const unsigned char *sha1)
|
||||
{
|
||||
return llist_insert(list, list->back, sha1);
|
||||
}
|
||||
|
||||
static inline struct llist_item *llist_insert_sorted_unique(struct llist *list, unsigned char *sha1, struct llist_item *hint)
|
||||
static inline struct llist_item *llist_insert_sorted_unique(struct llist *list,
|
||||
const unsigned char *sha1, struct llist_item *hint)
|
||||
{
|
||||
struct llist_item *prev = NULL, *l;
|
||||
|
||||
@@ -246,12 +248,12 @@ static struct pack_list * pack_list_difference(const struct pack_list *A,
|
||||
static void cmp_two_packs(struct pack_list *p1, struct pack_list *p2)
|
||||
{
|
||||
int p1_off, p2_off;
|
||||
unsigned char *p1_base, *p2_base;
|
||||
const unsigned char *p1_base, *p2_base;
|
||||
struct llist_item *p1_hint = NULL, *p2_hint = NULL;
|
||||
|
||||
p1_off = p2_off = 256 * 4 + 4;
|
||||
p1_base = (unsigned char *) p1->pack->index_base;
|
||||
p2_base = (unsigned char *) p2->pack->index_base;
|
||||
p1_base = p1->pack->index_data;
|
||||
p2_base = p2->pack->index_data;
|
||||
|
||||
while (p1_off <= p1->pack->index_size - 3 * 20 &&
|
||||
p2_off <= p2->pack->index_size - 3 * 20)
|
||||
@@ -351,11 +353,11 @@ static size_t sizeof_union(struct packed_git *p1, struct packed_git *p2)
|
||||
{
|
||||
size_t ret = 0;
|
||||
int p1_off, p2_off;
|
||||
unsigned char *p1_base, *p2_base;
|
||||
const unsigned char *p1_base, *p2_base;
|
||||
|
||||
p1_off = p2_off = 256 * 4 + 4;
|
||||
p1_base = (unsigned char *)p1->index_base;
|
||||
p2_base = (unsigned char *)p2->index_base;
|
||||
p1_base = p1->index_data;
|
||||
p2_base = p2->index_data;
|
||||
|
||||
while (p1_off <= p1->index_size - 3 * 20 &&
|
||||
p2_off <= p2->index_size - 3 * 20)
|
||||
@@ -534,7 +536,7 @@ static struct pack_list * add_pack(struct packed_git *p)
|
||||
{
|
||||
struct pack_list l;
|
||||
size_t off;
|
||||
unsigned char *base;
|
||||
const unsigned char *base;
|
||||
|
||||
if (!p->pack_local && !(alt_odb || verbose))
|
||||
return NULL;
|
||||
@@ -543,7 +545,7 @@ static struct pack_list * add_pack(struct packed_git *p)
|
||||
llist_init(&l.all_objects);
|
||||
|
||||
off = 256 * 4 + 4;
|
||||
base = (unsigned char *)p->index_base;
|
||||
base = p->index_data;
|
||||
while (off <= p->index_size - 3 * 20) {
|
||||
llist_insert_back(l.all_objects, base + off);
|
||||
off += 24;
|
||||
|
||||
30
pack.h
30
pack.h
@@ -16,24 +16,15 @@ struct pack_header {
|
||||
};
|
||||
|
||||
/*
|
||||
* Packed object index header
|
||||
*
|
||||
* struct pack_idx_header {
|
||||
* uint32_t idx_signature;
|
||||
* uint32_t idx_version;
|
||||
* };
|
||||
*
|
||||
* Note: this header isn't active yet. In future versions of git
|
||||
* we may change the index file format. At that time we would start
|
||||
* the first four bytes of the new index format with this signature,
|
||||
* as all older git binaries would find this value illegal and abort
|
||||
* reading the file.
|
||||
* The first four bytes of index formats later than version 1 should
|
||||
* start with this signature, as all older git binaries would find this
|
||||
* value illegal and abort reading the file.
|
||||
*
|
||||
* This is the case because the number of objects in a packfile
|
||||
* cannot exceed 1,431,660,000 as every object would need at least
|
||||
* 3 bytes of data and the overall packfile cannot exceed 4 GiB due
|
||||
* to the 32 bit offsets used by the index. Clearly the signature
|
||||
* exceeds this maximum.
|
||||
* 3 bytes of data and the overall packfile cannot exceed 4 GiB with
|
||||
* version 1 of the index file due to the offsets limited to 32 bits.
|
||||
* Clearly the signature exceeds this maximum.
|
||||
*
|
||||
* Very old git binaries will also compare the first 4 bytes to the
|
||||
* next 4 bytes in the index and abort with a "non-monotonic index"
|
||||
@@ -43,6 +34,15 @@ struct pack_header {
|
||||
*/
|
||||
#define PACK_IDX_SIGNATURE 0xff744f63 /* "\377tOc" */
|
||||
|
||||
/*
|
||||
* Packed object index header
|
||||
*/
|
||||
struct pack_idx_header {
|
||||
uint32_t idx_signature;
|
||||
uint32_t idx_version;
|
||||
};
|
||||
|
||||
|
||||
extern int verify_pack(struct packed_git *, int);
|
||||
|
||||
#define PH_ERROR_EOF (-1)
|
||||
|
||||
@@ -382,10 +382,10 @@ static const char *unpack(void)
|
||||
}
|
||||
} else {
|
||||
const char *keeper[6];
|
||||
int fd[2], s, len, status;
|
||||
pid_t pid;
|
||||
int s, len, status;
|
||||
char keep_arg[256];
|
||||
char packname[46];
|
||||
struct child_process ip;
|
||||
|
||||
s = sprintf(keep_arg, "--keep=receive-pack %i on ", getpid());
|
||||
if (gethostname(keep_arg + s, sizeof(keep_arg) - s))
|
||||
@@ -397,11 +397,11 @@ static const char *unpack(void)
|
||||
keeper[3] = hdr_arg;
|
||||
keeper[4] = keep_arg;
|
||||
keeper[5] = NULL;
|
||||
|
||||
if (pipe(fd) < 0)
|
||||
return "index-pack pipe failed";
|
||||
pid = spawnv_git_cmd(keeper, NULL, fd);
|
||||
if (pid < 0)
|
||||
memset(&ip, 0, sizeof(ip));
|
||||
ip.argv = keeper;
|
||||
ip.out = -1;
|
||||
ip.git_cmd = 1;
|
||||
if (start_command(&ip))
|
||||
return "index-pack fork failed";
|
||||
|
||||
/*
|
||||
@@ -412,9 +412,8 @@ static const char *unpack(void)
|
||||
* later on. If we don't get that then tough luck with it.
|
||||
*/
|
||||
for (len = 0;
|
||||
len < 46 && (s = xread(fd[0], packname+len, 46-len)) > 0;
|
||||
len < 46 && (s = xread(ip.out, packname+len, 46-len)) > 0;
|
||||
len += s);
|
||||
close(fd[0]);
|
||||
if (len == 46 && packname[45] == '\n' &&
|
||||
memcmp(packname, "keep\t", 5) == 0) {
|
||||
char path[PATH_MAX];
|
||||
@@ -424,14 +423,8 @@ static const char *unpack(void)
|
||||
pack_lockfile = xstrdup(path);
|
||||
}
|
||||
|
||||
/* Then wrap our index-pack process. */
|
||||
while (waitpid(pid, &status, 0) < 0)
|
||||
if (errno != EINTR)
|
||||
return "waitpid failed";
|
||||
if (WIFEXITED(status)) {
|
||||
int code = WEXITSTATUS(status);
|
||||
if (code)
|
||||
return "index-pack exited with error code";
|
||||
status = finish_command(&ip);
|
||||
if (!status) {
|
||||
reprepare_packed_git();
|
||||
return NULL;
|
||||
}
|
||||
@@ -485,7 +478,7 @@ int main(int argc, char **argv)
|
||||
if (!dir)
|
||||
usage(receive_pack_usage);
|
||||
|
||||
if(!enter_repo(dir, 0))
|
||||
if (!enter_repo(dir, 0))
|
||||
die("'%s': unable to chdir or not a git archive", dir);
|
||||
|
||||
if (is_repository_shallow())
|
||||
|
||||
17
revision.c
17
revision.c
@@ -213,6 +213,13 @@ static int everybody_uninteresting(struct commit_list *orig)
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* The goal is to get REV_TREE_NEW as the result only if the
|
||||
* diff consists of all '+' (and no other changes), and
|
||||
* REV_TREE_DIFFERENT otherwise (of course if the trees are
|
||||
* the same we want REV_TREE_SAME). That means that once we
|
||||
* get to REV_TREE_DIFFERENT, we do not have to look any further.
|
||||
*/
|
||||
static int tree_difference = REV_TREE_SAME;
|
||||
|
||||
static void file_add_remove(struct diff_options *options,
|
||||
@@ -236,6 +243,8 @@ static void file_add_remove(struct diff_options *options,
|
||||
diff = REV_TREE_NEW;
|
||||
}
|
||||
tree_difference = diff;
|
||||
if (tree_difference == REV_TREE_DIFFERENT)
|
||||
options->has_changes = 1;
|
||||
}
|
||||
|
||||
static void file_change(struct diff_options *options,
|
||||
@@ -245,6 +254,7 @@ static void file_change(struct diff_options *options,
|
||||
const char *base, const char *path)
|
||||
{
|
||||
tree_difference = REV_TREE_DIFFERENT;
|
||||
options->has_changes = 1;
|
||||
}
|
||||
|
||||
int rev_compare_tree(struct rev_info *revs, struct tree *t1, struct tree *t2)
|
||||
@@ -254,6 +264,7 @@ int rev_compare_tree(struct rev_info *revs, struct tree *t1, struct tree *t2)
|
||||
if (!t2)
|
||||
return REV_TREE_DIFFERENT;
|
||||
tree_difference = REV_TREE_SAME;
|
||||
revs->pruning.has_changes = 0;
|
||||
if (diff_tree_sha1(t1->object.sha1, t2->object.sha1, "",
|
||||
&revs->pruning) < 0)
|
||||
return REV_TREE_DIFFERENT;
|
||||
@@ -277,11 +288,12 @@ int rev_same_tree_as_empty(struct rev_info *revs, struct tree *t1)
|
||||
empty.buf = "";
|
||||
empty.size = 0;
|
||||
|
||||
tree_difference = 0;
|
||||
tree_difference = REV_TREE_SAME;
|
||||
revs->pruning.has_changes = 0;
|
||||
retval = diff_tree(&empty, &real, "", &revs->pruning);
|
||||
free(tree);
|
||||
|
||||
return retval >= 0 && !tree_difference;
|
||||
return retval >= 0 && (tree_difference == REV_TREE_SAME);
|
||||
}
|
||||
|
||||
static void try_to_simplify_commit(struct rev_info *revs, struct commit *commit)
|
||||
@@ -545,6 +557,7 @@ void init_revisions(struct rev_info *revs, const char *prefix)
|
||||
revs->ignore_merges = 1;
|
||||
revs->simplify_history = 1;
|
||||
revs->pruning.recursive = 1;
|
||||
revs->pruning.quiet = 1;
|
||||
revs->pruning.add_remove = file_add_remove;
|
||||
revs->pruning.change = file_change;
|
||||
revs->lifo = 1;
|
||||
|
||||
@@ -11,10 +11,11 @@ static inline void close_pair(int fd[2])
|
||||
|
||||
int start_command(struct child_process *cmd)
|
||||
{
|
||||
int need_in = !cmd->no_stdin && cmd->in < 0;
|
||||
int need_in, need_out;
|
||||
int fdin[2] = { -1, -1 };
|
||||
int fd_o[2] = { -1, -1 };
|
||||
int fdout[2] = { -1, -1 };
|
||||
|
||||
need_in = !cmd->no_stdin && cmd->in < 0;
|
||||
if (need_in) {
|
||||
if (pipe(fdin) < 0)
|
||||
return -ERR_RUN_COMMAND_PIPE;
|
||||
@@ -22,27 +23,49 @@ int start_command(struct child_process *cmd)
|
||||
cmd->close_in = 1;
|
||||
}
|
||||
|
||||
need_out = !cmd->no_stdout
|
||||
&& !cmd->stdout_to_stderr
|
||||
&& cmd->out < 0;
|
||||
if (need_out) {
|
||||
if (pipe(fdout) < 0) {
|
||||
if (need_in)
|
||||
close_pair(fdin);
|
||||
return -ERR_RUN_COMMAND_PIPE;
|
||||
}
|
||||
cmd->out = fdout[0];
|
||||
cmd->close_out = 1;
|
||||
}
|
||||
|
||||
{
|
||||
if (cmd->no_stdin) {
|
||||
if (cmd->no_stdin)
|
||||
fdin[0] = open("/dev/null", O_RDWR);
|
||||
} else if (need_in) {
|
||||
else if (need_in) {
|
||||
/* nothing */
|
||||
} else if (cmd->in) {
|
||||
fdin[0] = cmd->in;
|
||||
}
|
||||
|
||||
if (cmd->stdout_to_stderr)
|
||||
fd_o[1] = dup(2);
|
||||
if (cmd->no_stdout)
|
||||
fdout[1] = open("/dev/null", O_RDWR);
|
||||
else if (cmd->stdout_to_stderr)
|
||||
fdout[1] = dup(2);
|
||||
else if (need_out) {
|
||||
/* nothing */
|
||||
} else if (cmd->out > 1) {
|
||||
fdout[1] = cmd->out;
|
||||
}
|
||||
|
||||
if (cmd->git_cmd) {
|
||||
cmd->pid = spawnv_git_cmd(cmd->argv, fdin, fd_o);
|
||||
cmd->pid = spawnv_git_cmd(cmd->argv, fdin, fdout);
|
||||
} else {
|
||||
cmd->pid = spawnvpe_pipe(cmd->argv[0], cmd->argv, environ, fdin, fd_o);
|
||||
cmd->pid = spawnvpe_pipe(cmd->argv[0], cmd->argv, environ, fdin, fdout);
|
||||
}
|
||||
}
|
||||
if (cmd->pid < 0) {
|
||||
if (need_in) {
|
||||
if (need_in)
|
||||
close_pair(fdin);
|
||||
}
|
||||
if (need_out)
|
||||
close_pair(fdout);
|
||||
return -ERR_RUN_COMMAND_FORK;
|
||||
}
|
||||
|
||||
@@ -53,6 +76,8 @@ int finish_command(struct child_process *cmd)
|
||||
{
|
||||
if (cmd->close_in)
|
||||
close(cmd->in);
|
||||
if (cmd->close_out)
|
||||
close(cmd->out);
|
||||
|
||||
for (;;) {
|
||||
int status, code;
|
||||
|
||||
@@ -15,8 +15,11 @@ struct child_process {
|
||||
const char **argv;
|
||||
pid_t pid;
|
||||
int in;
|
||||
int out;
|
||||
unsigned close_in:1;
|
||||
unsigned close_out:1;
|
||||
unsigned no_stdin:1;
|
||||
unsigned no_stdout:1;
|
||||
unsigned git_cmd:1; /* if this is to be git sub-command */
|
||||
unsigned stdout_to_stderr:1;
|
||||
};
|
||||
|
||||
49
send-pack.c
49
send-pack.c
@@ -3,7 +3,7 @@
|
||||
#include "tag.h"
|
||||
#include "refs.h"
|
||||
#include "pkt-line.h"
|
||||
#include "exec_cmd.h"
|
||||
#include "run-command.h"
|
||||
|
||||
static const char send_pack_usage[] =
|
||||
"git-send-pack [--all] [--force] [--receive-pack=<git-receive-pack>] [--verbose] [--thin] [<host>:]<directory> [<ref>...]\n"
|
||||
@@ -19,16 +19,12 @@ static int use_thin_pack;
|
||||
*/
|
||||
static int pack_objects(int fd, struct ref *refs)
|
||||
{
|
||||
int pipe_fd[2];
|
||||
int pack_fd[2] = { -1, fd };
|
||||
pid_t pid;
|
||||
|
||||
/*
|
||||
* The child becomes pack-objects --revs; we feed
|
||||
* the revision parameters to it via its stdin and
|
||||
* let its stdout go back to the other end.
|
||||
*/
|
||||
static const char *args[] = {
|
||||
const char *args[] = {
|
||||
"pack-objects",
|
||||
"--all-progress",
|
||||
"--revs",
|
||||
@@ -36,20 +32,22 @@ static int pack_objects(int fd, struct ref *refs)
|
||||
NULL,
|
||||
NULL,
|
||||
};
|
||||
struct child_process po;
|
||||
|
||||
if (use_thin_pack)
|
||||
args[4] = "--thin";
|
||||
|
||||
if (pipe(pipe_fd) < 0)
|
||||
return error("send-pack: pipe failed");
|
||||
pid = spawnv_git_cmd(args, pipe_fd, pack_fd);
|
||||
if (pid < 0)
|
||||
return error("send-pack: unable to fork git-pack-objects");
|
||||
memset(&po, 0, sizeof(po));
|
||||
po.argv = args;
|
||||
po.in = -1;
|
||||
po.out = fd;
|
||||
po.git_cmd = 1;
|
||||
if (start_command(&po))
|
||||
die("git-pack-objects failed (%s)", strerror(errno));
|
||||
|
||||
/*
|
||||
* We feed the pack-objects we just spawned with revision
|
||||
* parameters by writing to the pipe.
|
||||
*/
|
||||
|
||||
while (refs) {
|
||||
char buf[42];
|
||||
|
||||
@@ -58,38 +56,23 @@ static int pack_objects(int fd, struct ref *refs)
|
||||
memcpy(buf + 1, sha1_to_hex(refs->old_sha1), 40);
|
||||
buf[0] = '^';
|
||||
buf[41] = '\n';
|
||||
if (!write_or_whine(pipe_fd[1], buf, 42,
|
||||
if (!write_or_whine(po.in, buf, 42,
|
||||
"send-pack: send refs"))
|
||||
break;
|
||||
}
|
||||
if (!is_null_sha1(refs->new_sha1)) {
|
||||
memcpy(buf, sha1_to_hex(refs->new_sha1), 40);
|
||||
buf[40] = '\n';
|
||||
if (!write_or_whine(pipe_fd[1], buf, 41,
|
||||
if (!write_or_whine(po.in, buf, 41,
|
||||
"send-pack: send refs"))
|
||||
break;
|
||||
}
|
||||
refs = refs->next;
|
||||
}
|
||||
close(pipe_fd[1]);
|
||||
|
||||
for (;;) {
|
||||
int status, code;
|
||||
pid_t waiting = waitpid(pid, &status, 0);
|
||||
|
||||
if (waiting < 0) {
|
||||
if (errno == EINTR)
|
||||
continue;
|
||||
return error("waitpid failed (%s)", strerror(errno));
|
||||
}
|
||||
if ((waiting != pid) || WIFSIGNALED(status) ||
|
||||
!WIFEXITED(status))
|
||||
return error("pack-objects died with strange error");
|
||||
code = WEXITSTATUS(status);
|
||||
if (code)
|
||||
return -code;
|
||||
return 0;
|
||||
}
|
||||
if (finish_command(&po))
|
||||
return error("pack-objects died with strange error");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void unmark_and_free(struct commit_list *list, unsigned int mark)
|
||||
|
||||
173
sha1_file.c
173
sha1_file.c
@@ -440,16 +440,15 @@ void pack_report()
|
||||
pack_mapped, peak_pack_mapped);
|
||||
}
|
||||
|
||||
static int check_packed_git_idx(const char *path,
|
||||
unsigned long *idx_size_,
|
||||
void **idx_map_)
|
||||
static int check_packed_git_idx(const char *path, struct packed_git *p)
|
||||
{
|
||||
void *idx_map;
|
||||
uint32_t *index;
|
||||
struct pack_idx_header *hdr;
|
||||
size_t idx_size;
|
||||
uint32_t nr, i;
|
||||
uint32_t nr, i, *index;
|
||||
int fd = open(path, O_RDONLY);
|
||||
struct stat st;
|
||||
|
||||
if (fd < 0)
|
||||
return -1;
|
||||
if (fstat(fd, &st)) {
|
||||
@@ -464,15 +463,12 @@ static int check_packed_git_idx(const char *path,
|
||||
idx_map = xmmap(NULL, idx_size, PROT_READ, MAP_PRIVATE, fd, 0);
|
||||
close(fd);
|
||||
|
||||
index = idx_map;
|
||||
*idx_map_ = idx_map;
|
||||
*idx_size_ = idx_size;
|
||||
|
||||
/* a future index format would start with this, as older git
|
||||
* binaries would fail the non-monotonic index check below.
|
||||
* give a nicer warning to the user if we can.
|
||||
*/
|
||||
if (index[0] == htonl(PACK_IDX_SIGNATURE)) {
|
||||
hdr = idx_map;
|
||||
if (hdr->idx_signature == htonl(PACK_IDX_SIGNATURE)) {
|
||||
munmap(idx_map, idx_size);
|
||||
return error("index file %s is a newer version"
|
||||
" and is not supported by this binary"
|
||||
@@ -481,6 +477,7 @@ static int check_packed_git_idx(const char *path,
|
||||
}
|
||||
|
||||
nr = 0;
|
||||
index = idx_map;
|
||||
for (i = 0; i < 256; i++) {
|
||||
uint32_t n = ntohl(index[i]);
|
||||
if (n < nr) {
|
||||
@@ -502,6 +499,9 @@ static int check_packed_git_idx(const char *path,
|
||||
return error("wrong index file size in %s", path);
|
||||
}
|
||||
|
||||
p->index_version = 1;
|
||||
p->index_data = idx_map;
|
||||
p->index_size = idx_size;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -624,7 +624,7 @@ static int open_packed_git_1(struct packed_git *p)
|
||||
return error("end of packfile %s is unavailable", p->pack_name);
|
||||
if (read_in_full(p->pack_fd, sha1, sizeof(sha1)) != sizeof(sha1))
|
||||
return error("packfile %s signature is unavailable", p->pack_name);
|
||||
idx_sha1 = ((unsigned char *)p->index_base) + p->index_size - 40;
|
||||
idx_sha1 = ((unsigned char *)p->index_data) + p->index_size - 40;
|
||||
if (hashcmp(sha1, idx_sha1))
|
||||
return error("packfile %s does not match index", p->pack_name);
|
||||
return 0;
|
||||
@@ -720,38 +720,37 @@ unsigned char* use_pack(struct packed_git *p,
|
||||
return win->base + offset;
|
||||
}
|
||||
|
||||
struct packed_git *add_packed_git(char *path, int path_len, int local)
|
||||
struct packed_git *add_packed_git(const char *path, int path_len, int local)
|
||||
{
|
||||
struct stat st;
|
||||
struct packed_git *p;
|
||||
unsigned long idx_size;
|
||||
void *idx_map;
|
||||
unsigned char sha1[20];
|
||||
struct packed_git *p = xmalloc(sizeof(*p) + path_len + 2);
|
||||
|
||||
if (check_packed_git_idx(path, &idx_size, &idx_map))
|
||||
/*
|
||||
* Make sure a corresponding .pack file exists and that
|
||||
* the index looks sane.
|
||||
*/
|
||||
path_len -= strlen(".idx");
|
||||
if (path_len < 1)
|
||||
return NULL;
|
||||
|
||||
/* do we have a corresponding .pack file? */
|
||||
strcpy(path + path_len - 4, ".pack");
|
||||
if (stat(path, &st) || !S_ISREG(st.st_mode)) {
|
||||
munmap(idx_map, idx_size);
|
||||
memcpy(p->pack_name, path, path_len);
|
||||
strcpy(p->pack_name + path_len, ".pack");
|
||||
if (stat(p->pack_name, &st) || !S_ISREG(st.st_mode) ||
|
||||
check_packed_git_idx(path, p)) {
|
||||
free(p);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* ok, it looks sane as far as we can check without
|
||||
* actually mapping the pack file.
|
||||
*/
|
||||
p = xmalloc(sizeof(*p) + path_len + 2);
|
||||
strcpy(p->pack_name, path);
|
||||
p->index_size = idx_size;
|
||||
p->pack_size = st.st_size;
|
||||
p->index_base = idx_map;
|
||||
p->next = NULL;
|
||||
p->windows = NULL;
|
||||
p->pack_fd = -1;
|
||||
p->pack_local = local;
|
||||
p->mtime = st.st_mtime;
|
||||
if ((path_len > 44) && !get_sha1_hex(path + path_len - 44, sha1))
|
||||
hashcpy(p->sha1, sha1);
|
||||
if (path_len < 40 || get_sha1_hex(path + path_len - 40, p->sha1))
|
||||
hashclr(p->sha1);
|
||||
return p;
|
||||
}
|
||||
|
||||
@@ -761,23 +760,19 @@ struct packed_git *parse_pack_index(unsigned char *sha1)
|
||||
return parse_pack_index_file(sha1, path);
|
||||
}
|
||||
|
||||
struct packed_git *parse_pack_index_file(const unsigned char *sha1, char *idx_path)
|
||||
struct packed_git *parse_pack_index_file(const unsigned char *sha1,
|
||||
const char *idx_path)
|
||||
{
|
||||
struct packed_git *p;
|
||||
unsigned long idx_size;
|
||||
void *idx_map;
|
||||
char *path;
|
||||
const char *path = sha1_pack_name(sha1);
|
||||
struct packed_git *p = xmalloc(sizeof(*p) + strlen(path) + 2);
|
||||
|
||||
if (check_packed_git_idx(idx_path, &idx_size, &idx_map))
|
||||
if (check_packed_git_idx(idx_path, p)) {
|
||||
free(p);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
path = sha1_pack_name(sha1);
|
||||
|
||||
p = xmalloc(sizeof(*p) + strlen(path) + 2);
|
||||
strcpy(p->pack_name, path);
|
||||
p->index_size = idx_size;
|
||||
p->pack_size = 0;
|
||||
p->index_base = idx_map;
|
||||
p->next = NULL;
|
||||
p->windows = NULL;
|
||||
p->pack_fd = -1;
|
||||
@@ -1367,6 +1362,87 @@ static void *unpack_compressed_entry(struct packed_git *p,
|
||||
return buffer;
|
||||
}
|
||||
|
||||
#define MAX_DELTA_CACHE (256)
|
||||
|
||||
static size_t delta_base_cached;
|
||||
static struct delta_base_cache_entry {
|
||||
struct packed_git *p;
|
||||
off_t base_offset;
|
||||
unsigned long size;
|
||||
void *data;
|
||||
enum object_type type;
|
||||
} delta_base_cache[MAX_DELTA_CACHE];
|
||||
|
||||
static unsigned long pack_entry_hash(struct packed_git *p, off_t base_offset)
|
||||
{
|
||||
unsigned long hash;
|
||||
|
||||
hash = (unsigned long)p + (unsigned long)base_offset;
|
||||
hash += (hash >> 8) + (hash >> 16);
|
||||
return hash & 0xff;
|
||||
}
|
||||
|
||||
static void *cache_or_unpack_entry(struct packed_git *p, off_t base_offset,
|
||||
unsigned long *base_size, enum object_type *type, int keep_cache)
|
||||
{
|
||||
void *ret;
|
||||
unsigned long hash = pack_entry_hash(p, base_offset);
|
||||
struct delta_base_cache_entry *ent = delta_base_cache + hash;
|
||||
|
||||
ret = ent->data;
|
||||
if (ret && ent->p == p && ent->base_offset == base_offset)
|
||||
goto found_cache_entry;
|
||||
return unpack_entry(p, base_offset, type, base_size);
|
||||
|
||||
found_cache_entry:
|
||||
if (!keep_cache) {
|
||||
ent->data = NULL;
|
||||
delta_base_cached -= ent->size;
|
||||
}
|
||||
else {
|
||||
ret = xmalloc(ent->size + 1);
|
||||
memcpy(ret, ent->data, ent->size);
|
||||
((char *)ret)[ent->size] = 0;
|
||||
}
|
||||
*type = ent->type;
|
||||
*base_size = ent->size;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline void release_delta_base_cache(struct delta_base_cache_entry *ent)
|
||||
{
|
||||
if (ent->data) {
|
||||
free(ent->data);
|
||||
ent->data = NULL;
|
||||
delta_base_cached -= ent->size;
|
||||
}
|
||||
}
|
||||
|
||||
static void add_delta_base_cache(struct packed_git *p, off_t base_offset,
|
||||
void *base, unsigned long base_size, enum object_type type)
|
||||
{
|
||||
unsigned long i, hash = pack_entry_hash(p, base_offset);
|
||||
struct delta_base_cache_entry *ent = delta_base_cache + hash;
|
||||
|
||||
release_delta_base_cache(ent);
|
||||
delta_base_cached += base_size;
|
||||
for (i = 0; delta_base_cached > delta_base_cache_limit
|
||||
&& i < ARRAY_SIZE(delta_base_cache); i++) {
|
||||
struct delta_base_cache_entry *f = delta_base_cache + i;
|
||||
if (f->type == OBJ_BLOB)
|
||||
release_delta_base_cache(f);
|
||||
}
|
||||
for (i = 0; delta_base_cached > delta_base_cache_limit
|
||||
&& i < ARRAY_SIZE(delta_base_cache); i++)
|
||||
release_delta_base_cache(delta_base_cache + i);
|
||||
|
||||
ent->p = p;
|
||||
ent->base_offset = base_offset;
|
||||
ent->type = type;
|
||||
ent->data = base;
|
||||
ent->size = base_size;
|
||||
}
|
||||
|
||||
static void *unpack_delta_entry(struct packed_git *p,
|
||||
struct pack_window **w_curs,
|
||||
off_t curpos,
|
||||
@@ -1380,7 +1456,7 @@ static void *unpack_delta_entry(struct packed_git *p,
|
||||
off_t base_offset;
|
||||
|
||||
base_offset = get_delta_base(p, w_curs, &curpos, *type, obj_offset);
|
||||
base = unpack_entry(p, base_offset, type, &base_size);
|
||||
base = cache_or_unpack_entry(p, base_offset, &base_size, type, 0);
|
||||
if (!base)
|
||||
die("failed to read delta base object"
|
||||
" at %"PRIuMAX" from %s",
|
||||
@@ -1393,7 +1469,7 @@ static void *unpack_delta_entry(struct packed_git *p,
|
||||
if (!result)
|
||||
die("failed to apply delta");
|
||||
free(delta_data);
|
||||
free(base);
|
||||
add_delta_base_cache(p, base_offset, base, base_size, *type);
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -1433,24 +1509,27 @@ uint32_t num_packed_objects(const struct packed_git *p)
|
||||
int nth_packed_object_sha1(const struct packed_git *p, uint32_t n,
|
||||
unsigned char* sha1)
|
||||
{
|
||||
void *index = p->index_base + 256;
|
||||
const unsigned char *index = p->index_data;
|
||||
index += 4 * 256;
|
||||
if (num_packed_objects(p) <= n)
|
||||
return -1;
|
||||
hashcpy(sha1, (unsigned char *) index + (24 * n) + 4);
|
||||
hashcpy(sha1, index + 24 * n + 4);
|
||||
return 0;
|
||||
}
|
||||
|
||||
off_t find_pack_entry_one(const unsigned char *sha1,
|
||||
struct packed_git *p)
|
||||
{
|
||||
uint32_t *level1_ofs = p->index_base;
|
||||
const uint32_t *level1_ofs = p->index_data;
|
||||
int hi = ntohl(level1_ofs[*sha1]);
|
||||
int lo = ((*sha1 == 0x0) ? 0 : ntohl(level1_ofs[*sha1 - 1]));
|
||||
void *index = p->index_base + 256;
|
||||
const unsigned char *index = p->index_data;
|
||||
|
||||
index += 4 * 256;
|
||||
|
||||
do {
|
||||
int mi = (lo + hi) / 2;
|
||||
int cmp = hashcmp((unsigned char *)index + (24 * mi) + 4, sha1);
|
||||
int cmp = hashcmp(index + 24 * mi + 4, sha1);
|
||||
if (!cmp)
|
||||
return ntohl(*((uint32_t *)((char *)index + (24 * mi))));
|
||||
if (cmp > 0)
|
||||
@@ -1574,7 +1653,7 @@ static void *read_packed_sha1(const unsigned char *sha1,
|
||||
if (!find_pack_entry(sha1, &e, NULL))
|
||||
return NULL;
|
||||
else
|
||||
return unpack_entry(e.p, e.offset, type, size);
|
||||
return cache_or_unpack_entry(e.p, e.offset, size, type, 1);
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -147,9 +147,15 @@ test_expect_success 'test overriding tracking setup via --no-track' \
|
||||
git-config remote.local.fetch refs/heads/*:refs/remotes/local/* &&
|
||||
(git-show-ref -q refs/remotes/local/master || git-fetch local) &&
|
||||
git-branch --no-track my2 local/master &&
|
||||
git-config branch.autosetupmerge false &&
|
||||
! test $(git-config branch.my2.remote) = local &&
|
||||
! test $(git-config branch.my2.merge) = refs/heads/master'
|
||||
|
||||
test_expect_success 'test local tracking setup' \
|
||||
'git branch --track my6 s &&
|
||||
test $(git-config branch.my6.remote) = . &&
|
||||
test $(git-config branch.my6.merge) = refs/heads/s'
|
||||
|
||||
# Keep this test last, as it changes the current branch
|
||||
cat >expect <<EOF
|
||||
0000000000000000000000000000000000000000 $HEAD $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> 1117150200 +0000 branch: Created from master
|
||||
|
||||
79
t/t4017-diff-retval.sh
Executable file
79
t/t4017-diff-retval.sh
Executable file
@@ -0,0 +1,79 @@
|
||||
#!/bin/sh
|
||||
|
||||
test_description='Return value of diffs'
|
||||
|
||||
. ./test-lib.sh
|
||||
|
||||
test_expect_success 'setup' '
|
||||
echo 1 >a &&
|
||||
git add . &&
|
||||
git commit -m first &&
|
||||
echo 2 >b &&
|
||||
git add . &&
|
||||
git commit -a -m second
|
||||
'
|
||||
|
||||
test_expect_success 'git diff-tree HEAD^ HEAD' '
|
||||
git diff-tree --exit-code HEAD^ HEAD
|
||||
test $? = 1
|
||||
'
|
||||
test_expect_success 'git diff-tree HEAD^ HEAD -- a' '
|
||||
git diff-tree --exit-code HEAD^ HEAD -- a
|
||||
test $? = 0
|
||||
'
|
||||
test_expect_success 'git diff-tree HEAD^ HEAD -- b' '
|
||||
git diff-tree --exit-code HEAD^ HEAD -- b
|
||||
test $? = 1
|
||||
'
|
||||
test_expect_success 'echo HEAD | git diff-tree --stdin' '
|
||||
echo $(git rev-parse HEAD) | git diff-tree --exit-code --stdin
|
||||
test $? = 1
|
||||
'
|
||||
test_expect_success 'git diff-tree HEAD HEAD' '
|
||||
git diff-tree --exit-code HEAD HEAD
|
||||
test $? = 0
|
||||
'
|
||||
test_expect_success 'git diff-files' '
|
||||
git diff-files --exit-code
|
||||
test $? = 0
|
||||
'
|
||||
test_expect_success 'git diff-index --cached HEAD' '
|
||||
git diff-index --exit-code --cached HEAD
|
||||
test $? = 0
|
||||
'
|
||||
test_expect_success 'git diff-index --cached HEAD^' '
|
||||
git diff-index --exit-code --cached HEAD^
|
||||
test $? = 1
|
||||
'
|
||||
test_expect_success 'git diff-index --cached HEAD^' '
|
||||
echo text >>b &&
|
||||
echo 3 >c &&
|
||||
git add . && {
|
||||
git diff-index --exit-code --cached HEAD^
|
||||
test $? = 1
|
||||
}
|
||||
'
|
||||
test_expect_success 'git diff-tree -Stext HEAD^ HEAD -- b' '
|
||||
git commit -m "text in b" && {
|
||||
git diff-tree -p --exit-code -Stext HEAD^ HEAD -- b
|
||||
test $? = 1
|
||||
}
|
||||
'
|
||||
test_expect_success 'git diff-tree -Snot-found HEAD^ HEAD -- b' '
|
||||
git diff-tree -p --exit-code -Snot-found HEAD^ HEAD -- b
|
||||
test $? = 0
|
||||
'
|
||||
test_expect_success 'git diff-files' '
|
||||
echo 3 >>c && {
|
||||
git diff-files --exit-code
|
||||
test $? = 1
|
||||
}
|
||||
'
|
||||
test_expect_success 'git diff-index --cached HEAD' '
|
||||
git update-index c && {
|
||||
git diff-index --exit-code --cached HEAD
|
||||
test $? = 1
|
||||
}
|
||||
'
|
||||
|
||||
test_done
|
||||
80
t/t4017-quiet.sh
Executable file
80
t/t4017-quiet.sh
Executable file
@@ -0,0 +1,80 @@
|
||||
#!/bin/sh
|
||||
|
||||
test_description='Return value of diffs'
|
||||
|
||||
. ./test-lib.sh
|
||||
|
||||
test_expect_success 'setup' '
|
||||
echo 1 >a &&
|
||||
git add . &&
|
||||
git commit -m first &&
|
||||
echo 2 >b &&
|
||||
git add . &&
|
||||
git commit -a -m second
|
||||
'
|
||||
|
||||
test_expect_success 'git diff-tree HEAD^ HEAD' '
|
||||
git diff-tree --quiet HEAD^ HEAD >cnt
|
||||
test $? = 1 && test $(wc -l <cnt) = 0
|
||||
'
|
||||
test_expect_success 'git diff-tree HEAD^ HEAD -- a' '
|
||||
git diff-tree --quiet HEAD^ HEAD -- a >cnt
|
||||
test $? = 0 && test $(wc -l <cnt) = 0
|
||||
'
|
||||
test_expect_success 'git diff-tree HEAD^ HEAD -- b' '
|
||||
git diff-tree --quiet HEAD^ HEAD -- b >cnt
|
||||
test $? = 1 && test $(wc -l <cnt) = 0
|
||||
'
|
||||
# this diff outputs one line: sha1 of the given head
|
||||
test_expect_success 'echo HEAD | git diff-tree --stdin' '
|
||||
echo $(git rev-parse HEAD) | git diff-tree --quiet --stdin >cnt
|
||||
test $? = 1 && test $(wc -l <cnt) = 1
|
||||
'
|
||||
test_expect_success 'git diff-tree HEAD HEAD' '
|
||||
git diff-tree --quiet HEAD HEAD >cnt
|
||||
test $? = 0 && test $(wc -l <cnt) = 0
|
||||
'
|
||||
test_expect_success 'git diff-files' '
|
||||
git diff-files --quiet >cnt
|
||||
test $? = 0 && test $(wc -l <cnt) = 0
|
||||
'
|
||||
test_expect_success 'git diff-index --cached HEAD' '
|
||||
git diff-index --quiet --cached HEAD >cnt
|
||||
test $? = 0 && test $(wc -l <cnt) = 0
|
||||
'
|
||||
test_expect_success 'git diff-index --cached HEAD^' '
|
||||
git diff-index --quiet --cached HEAD^ >cnt
|
||||
test $? = 1 && test $(wc -l <cnt) = 0
|
||||
'
|
||||
test_expect_success 'git diff-index --cached HEAD^' '
|
||||
echo text >>b &&
|
||||
echo 3 >c &&
|
||||
git add . && {
|
||||
git diff-index --quiet --cached HEAD^ >cnt
|
||||
test $? = 1 && test $(wc -l <cnt) = 0
|
||||
}
|
||||
'
|
||||
test_expect_success 'git diff-tree -Stext HEAD^ HEAD -- b' '
|
||||
git commit -m "text in b" && {
|
||||
git diff-tree --quiet -Stext HEAD^ HEAD -- b >cnt
|
||||
test $? = 1 && test $(wc -l <cnt) = 0
|
||||
}
|
||||
'
|
||||
test_expect_success 'git diff-tree -Snot-found HEAD^ HEAD -- b' '
|
||||
git diff-tree --quiet -Snot-found HEAD^ HEAD -- b >cnt
|
||||
test $? = 0 && test $(wc -l <cnt) = 0
|
||||
'
|
||||
test_expect_success 'git diff-files' '
|
||||
echo 3 >>c && {
|
||||
git diff-files --quiet >cnt
|
||||
test $? = 1 && test $(wc -l <cnt) = 0
|
||||
}
|
||||
'
|
||||
test_expect_success 'git diff-index --cached HEAD' '
|
||||
git update-index c && {
|
||||
git diff-index --quiet --cached HEAD >cnt
|
||||
test $? = 1 && test $(wc -l <cnt) = 0
|
||||
}
|
||||
'
|
||||
|
||||
test_done
|
||||
@@ -80,7 +80,7 @@ test_expect_success \
|
||||
cd "$TRASH"
|
||||
|
||||
test_expect_success \
|
||||
'pack with delta' \
|
||||
'pack with REF_DELTA' \
|
||||
'pwd &&
|
||||
packname_2=$(git-pack-objects test-2 <obj-list)'
|
||||
|
||||
@@ -88,7 +88,7 @@ rm -fr .git2
|
||||
mkdir .git2
|
||||
|
||||
test_expect_success \
|
||||
'unpack with delta' \
|
||||
'unpack with REF_DELTA' \
|
||||
'GIT_OBJECT_DIRECTORY=.git2/objects &&
|
||||
export GIT_OBJECT_DIRECTORY &&
|
||||
git-init &&
|
||||
@@ -98,7 +98,7 @@ test_expect_success \
|
||||
unset GIT_OBJECT_DIRECTORY
|
||||
cd "$TRASH/.git2"
|
||||
test_expect_success \
|
||||
'check unpack with delta' \
|
||||
'check unpack with REF_DELTA' \
|
||||
'(cd ../.git && find objects -type f -print) |
|
||||
while read path
|
||||
do
|
||||
@@ -109,6 +109,42 @@ test_expect_success \
|
||||
done'
|
||||
cd "$TRASH"
|
||||
|
||||
test_expect_success \
|
||||
'pack with OFS_DELTA' \
|
||||
'pwd &&
|
||||
packname_3=$(git-pack-objects --delta-base-offset test-3 <obj-list)'
|
||||
|
||||
rm -fr .git2
|
||||
mkdir .git2
|
||||
|
||||
test_expect_success \
|
||||
'unpack with OFS_DELTA' \
|
||||
'GIT_OBJECT_DIRECTORY=.git2/objects &&
|
||||
export GIT_OBJECT_DIRECTORY &&
|
||||
git-init &&
|
||||
git-unpack-objects -n <test-3-${packname_3}.pack &&
|
||||
git-unpack-objects <test-3-${packname_3}.pack'
|
||||
|
||||
unset GIT_OBJECT_DIRECTORY
|
||||
cd "$TRASH/.git2"
|
||||
test_expect_success \
|
||||
'check unpack with OFS_DELTA' \
|
||||
'(cd ../.git && find objects -type f -print) |
|
||||
while read path
|
||||
do
|
||||
cmp $path ../.git/$path || {
|
||||
echo $path differs.
|
||||
return 1
|
||||
}
|
||||
done'
|
||||
cd "$TRASH"
|
||||
|
||||
test_expect_success \
|
||||
'compare delta flavors' \
|
||||
'size_2=`stat -c "%s" test-2-${packname_2}.pack` &&
|
||||
size_3=`stat -c "%s" test-3-${packname_3}.pack` &&
|
||||
test $size_2 -gt $size_3'
|
||||
|
||||
rm -fr .git2
|
||||
mkdir .git2
|
||||
|
||||
@@ -127,12 +163,11 @@ test_expect_success \
|
||||
} >current &&
|
||||
diff expect current'
|
||||
|
||||
|
||||
test_expect_success \
|
||||
'use packed deltified objects' \
|
||||
'use packed deltified (REF_DELTA) objects' \
|
||||
'GIT_OBJECT_DIRECTORY=.git2/objects &&
|
||||
export GIT_OBJECT_DIRECTORY &&
|
||||
rm -f .git2/objects/pack/test-?.idx &&
|
||||
rm .git2/objects/pack/test-* &&
|
||||
cp test-2-${packname_2}.pack test-2-${packname_2}.idx .git2/objects/pack && {
|
||||
git-diff-tree --root -p $commit &&
|
||||
while read object
|
||||
@@ -143,11 +178,28 @@ test_expect_success \
|
||||
} >current &&
|
||||
diff expect current'
|
||||
|
||||
test_expect_success \
|
||||
'use packed deltified (OFS_DELTA) objects' \
|
||||
'GIT_OBJECT_DIRECTORY=.git2/objects &&
|
||||
export GIT_OBJECT_DIRECTORY &&
|
||||
rm .git2/objects/pack/test-* &&
|
||||
cp test-3-${packname_3}.pack test-3-${packname_3}.idx .git2/objects/pack && {
|
||||
git-diff-tree --root -p $commit &&
|
||||
while read object
|
||||
do
|
||||
t=`git-cat-file -t $object` &&
|
||||
git-cat-file $t $object || return 1
|
||||
done <obj-list
|
||||
} >current &&
|
||||
diff expect current'
|
||||
|
||||
unset GIT_OBJECT_DIRECTORY
|
||||
|
||||
test_expect_success \
|
||||
'verify pack' \
|
||||
'git-verify-pack test-1-${packname_1}.idx test-2-${packname_2}.idx'
|
||||
'git-verify-pack test-1-${packname_1}.idx \
|
||||
test-2-${packname_2}.idx \
|
||||
test-3-${packname_3}.idx'
|
||||
|
||||
test_expect_success \
|
||||
'verify-pack catches mismatched .idx and .pack files' \
|
||||
@@ -208,6 +260,13 @@ test_expect_success \
|
||||
git-index-pack test-3.pack &&
|
||||
cmp test-3.idx test-2-${packname_2}.idx &&
|
||||
|
||||
cp test-3-${packname_3}.pack test-3.pack &&
|
||||
git-index-pack -o tmp.idx test-3-${packname_3}.pack &&
|
||||
cmp tmp.idx test-3-${packname_3}.idx &&
|
||||
|
||||
git-index-pack test-3.pack &&
|
||||
cmp test-3.idx test-3-${packname_3}.idx &&
|
||||
|
||||
:'
|
||||
|
||||
test_done
|
||||
|
||||
@@ -29,5 +29,29 @@ test_expect_success 'checking the results' '
|
||||
diff file cloned/file
|
||||
'
|
||||
|
||||
test_expect_success 'test . as a remote' '
|
||||
|
||||
git branch copy master &&
|
||||
git config branch.copy.remote . &&
|
||||
git config branch.copy.merge refs/heads/master &&
|
||||
echo updated >file &&
|
||||
git commit -a -m updated &&
|
||||
git checkout copy &&
|
||||
test `cat file` = file &&
|
||||
git pull &&
|
||||
test `cat file` = updated
|
||||
'
|
||||
|
||||
test_expect_success 'the default remote . should not break explicit pull' '
|
||||
git checkout -b second master^ &&
|
||||
echo modified >file &&
|
||||
git commit -a -m modified &&
|
||||
git checkout copy &&
|
||||
git reset --hard HEAD^ &&
|
||||
test `cat file` = file &&
|
||||
git pull . second &&
|
||||
test `cat file` = modified
|
||||
'
|
||||
|
||||
test_done
|
||||
|
||||
|
||||
94
tree-diff.c
94
tree-diff.c
@@ -5,9 +5,8 @@
|
||||
#include "diff.h"
|
||||
#include "tree.h"
|
||||
|
||||
static char *malloc_base(const char *base, const char *path, int pathlen)
|
||||
static char *malloc_base(const char *base, int baselen, const char *path, int pathlen)
|
||||
{
|
||||
int baselen = strlen(base);
|
||||
char *newbase = xmalloc(baselen + pathlen + 2);
|
||||
memcpy(newbase, base, baselen);
|
||||
memcpy(newbase + baselen, path, pathlen);
|
||||
@@ -16,9 +15,9 @@ static char *malloc_base(const char *base, const char *path, int pathlen)
|
||||
}
|
||||
|
||||
static void show_entry(struct diff_options *opt, const char *prefix, struct tree_desc *desc,
|
||||
const char *base);
|
||||
const char *base, int baselen);
|
||||
|
||||
static int compare_tree_entry(struct tree_desc *t1, struct tree_desc *t2, const char *base, struct diff_options *opt)
|
||||
static int compare_tree_entry(struct tree_desc *t1, struct tree_desc *t2, const char *base, int baselen, struct diff_options *opt)
|
||||
{
|
||||
unsigned mode1, mode2;
|
||||
const char *path1, *path2;
|
||||
@@ -28,15 +27,15 @@ static int compare_tree_entry(struct tree_desc *t1, struct tree_desc *t2, const
|
||||
sha1 = tree_entry_extract(t1, &path1, &mode1);
|
||||
sha2 = tree_entry_extract(t2, &path2, &mode2);
|
||||
|
||||
pathlen1 = strlen(path1);
|
||||
pathlen2 = strlen(path2);
|
||||
pathlen1 = tree_entry_len(path1, sha1);
|
||||
pathlen2 = tree_entry_len(path2, sha2);
|
||||
cmp = base_name_compare(path1, pathlen1, mode1, path2, pathlen2, mode2);
|
||||
if (cmp < 0) {
|
||||
show_entry(opt, "-", t1, base);
|
||||
show_entry(opt, "-", t1, base, baselen);
|
||||
return -1;
|
||||
}
|
||||
if (cmp > 0) {
|
||||
show_entry(opt, "+", t2, base);
|
||||
show_entry(opt, "+", t2, base, baselen);
|
||||
return 1;
|
||||
}
|
||||
if (!opt->find_copies_harder && !hashcmp(sha1, sha2) && mode1 == mode2)
|
||||
@@ -47,14 +46,14 @@ static int compare_tree_entry(struct tree_desc *t1, struct tree_desc *t2, const
|
||||
* file, we need to consider it a remove and an add.
|
||||
*/
|
||||
if (S_ISDIR(mode1) != S_ISDIR(mode2)) {
|
||||
show_entry(opt, "-", t1, base);
|
||||
show_entry(opt, "+", t2, base);
|
||||
show_entry(opt, "-", t1, base, baselen);
|
||||
show_entry(opt, "+", t2, base, baselen);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (opt->recursive && S_ISDIR(mode1)) {
|
||||
int retval;
|
||||
char *newbase = malloc_base(base, path1, pathlen1);
|
||||
char *newbase = malloc_base(base, baselen, path1, pathlen1);
|
||||
if (opt->tree_in_recursive)
|
||||
opt->change(opt, mode1, mode2,
|
||||
sha1, sha2, base, path1);
|
||||
@@ -67,20 +66,28 @@ static int compare_tree_entry(struct tree_desc *t1, struct tree_desc *t2, const
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int interesting(struct tree_desc *desc, const char *base, struct diff_options *opt)
|
||||
/*
|
||||
* Is a tree entry interesting given the pathspec we have?
|
||||
*
|
||||
* Return:
|
||||
* - positive for yes
|
||||
* - zero for no
|
||||
* - negative for "no, and no subsequent entries will be either"
|
||||
*/
|
||||
static int tree_entry_interesting(struct tree_desc *desc, const char *base, int baselen, struct diff_options *opt)
|
||||
{
|
||||
const char *path;
|
||||
const unsigned char *sha1;
|
||||
unsigned mode;
|
||||
int i;
|
||||
int baselen, pathlen;
|
||||
int pathlen;
|
||||
|
||||
if (!opt->nr_paths)
|
||||
return 1;
|
||||
|
||||
(void)tree_entry_extract(desc, &path, &mode);
|
||||
sha1 = tree_entry_extract(desc, &path, &mode);
|
||||
|
||||
pathlen = strlen(path);
|
||||
baselen = strlen(base);
|
||||
pathlen = tree_entry_len(path, sha1);
|
||||
|
||||
for (i=0; i < opt->nr_paths; i++) {
|
||||
const char *match = opt->paths[i];
|
||||
@@ -121,18 +128,21 @@ static int interesting(struct tree_desc *desc, const char *base, struct diff_opt
|
||||
}
|
||||
|
||||
/* A whole sub-tree went away or appeared */
|
||||
static void show_tree(struct diff_options *opt, const char *prefix, struct tree_desc *desc, const char *base)
|
||||
static void show_tree(struct diff_options *opt, const char *prefix, struct tree_desc *desc, const char *base, int baselen)
|
||||
{
|
||||
while (desc->size) {
|
||||
if (interesting(desc, base, opt))
|
||||
show_entry(opt, prefix, desc, base);
|
||||
int show = tree_entry_interesting(desc, base, baselen, opt);
|
||||
if (show < 0)
|
||||
break;
|
||||
if (show)
|
||||
show_entry(opt, prefix, desc, base, baselen);
|
||||
update_tree_entry(desc);
|
||||
}
|
||||
}
|
||||
|
||||
/* A file entry went away or appeared */
|
||||
static void show_entry(struct diff_options *opt, const char *prefix, struct tree_desc *desc,
|
||||
const char *base)
|
||||
const char *base, int baselen)
|
||||
{
|
||||
unsigned mode;
|
||||
const char *path;
|
||||
@@ -140,7 +150,8 @@ static void show_entry(struct diff_options *opt, const char *prefix, struct tree
|
||||
|
||||
if (opt->recursive && S_ISDIR(mode)) {
|
||||
enum object_type type;
|
||||
char *newbase = malloc_base(base, path, strlen(path));
|
||||
int pathlen = tree_entry_len(path, sha1);
|
||||
char *newbase = malloc_base(base, baselen, path, pathlen);
|
||||
struct tree_desc inner;
|
||||
void *tree;
|
||||
|
||||
@@ -149,7 +160,7 @@ static void show_entry(struct diff_options *opt, const char *prefix, struct tree
|
||||
die("corrupt tree sha %s", sha1_to_hex(sha1));
|
||||
|
||||
inner.buf = tree;
|
||||
show_tree(opt, prefix, &inner, newbase);
|
||||
show_tree(opt, prefix, &inner, newbase, baselen + 1 + pathlen);
|
||||
|
||||
free(tree);
|
||||
free(newbase);
|
||||
@@ -158,28 +169,45 @@ static void show_entry(struct diff_options *opt, const char *prefix, struct tree
|
||||
}
|
||||
}
|
||||
|
||||
static void skip_uninteresting(struct tree_desc *t, const char *base, int baselen, struct diff_options *opt)
|
||||
{
|
||||
while (t->size) {
|
||||
int show = tree_entry_interesting(t, base, baselen, opt);
|
||||
if (!show) {
|
||||
update_tree_entry(t);
|
||||
continue;
|
||||
}
|
||||
/* Skip it all? */
|
||||
if (show < 0)
|
||||
t->size = 0;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
int diff_tree(struct tree_desc *t1, struct tree_desc *t2, const char *base, struct diff_options *opt)
|
||||
{
|
||||
while (t1->size | t2->size) {
|
||||
if (opt->nr_paths && t1->size && !interesting(t1, base, opt)) {
|
||||
update_tree_entry(t1);
|
||||
continue;
|
||||
}
|
||||
if (opt->nr_paths && t2->size && !interesting(t2, base, opt)) {
|
||||
update_tree_entry(t2);
|
||||
continue;
|
||||
int baselen = strlen(base);
|
||||
|
||||
for (;;) {
|
||||
if (opt->quiet && opt->has_changes)
|
||||
break;
|
||||
if (opt->nr_paths) {
|
||||
skip_uninteresting(t1, base, baselen, opt);
|
||||
skip_uninteresting(t2, base, baselen, opt);
|
||||
}
|
||||
if (!t1->size) {
|
||||
show_entry(opt, "+", t2, base);
|
||||
if (!t2->size)
|
||||
break;
|
||||
show_entry(opt, "+", t2, base, baselen);
|
||||
update_tree_entry(t2);
|
||||
continue;
|
||||
}
|
||||
if (!t2->size) {
|
||||
show_entry(opt, "-", t1, base);
|
||||
show_entry(opt, "-", t1, base, baselen);
|
||||
update_tree_entry(t1);
|
||||
continue;
|
||||
}
|
||||
switch (compare_tree_entry(t1, t2, base, opt)) {
|
||||
switch (compare_tree_entry(t1, t2, base, baselen, opt)) {
|
||||
case -1:
|
||||
update_tree_entry(t1);
|
||||
continue;
|
||||
|
||||
@@ -32,7 +32,7 @@ static void entry_clear(struct name_entry *a)
|
||||
static void entry_extract(struct tree_desc *t, struct name_entry *a)
|
||||
{
|
||||
a->sha1 = tree_entry_extract(t, &a->path, &a->mode);
|
||||
a->pathlen = strlen(a->path);
|
||||
a->pathlen = tree_entry_len(a->path, a->sha1);
|
||||
}
|
||||
|
||||
void update_tree_entry(struct tree_desc *desc)
|
||||
@@ -169,7 +169,7 @@ static int find_tree_entry(struct tree_desc *t, const char *name, unsigned char
|
||||
|
||||
sha1 = tree_entry_extract(t, &entry, mode);
|
||||
update_tree_entry(t);
|
||||
entrylen = strlen(entry);
|
||||
entrylen = tree_entry_len(entry, sha1);
|
||||
if (entrylen > namelen)
|
||||
continue;
|
||||
cmp = memcmp(name, entry, entrylen);
|
||||
|
||||
@@ -13,6 +13,11 @@ struct name_entry {
|
||||
int pathlen;
|
||||
};
|
||||
|
||||
static inline int tree_entry_len(const char *name, const unsigned char *sha1)
|
||||
{
|
||||
return (char *)sha1 - (char *)name - 1;
|
||||
}
|
||||
|
||||
void update_tree_entry(struct tree_desc *);
|
||||
const unsigned char *tree_entry_extract(struct tree_desc *, const char **, unsigned int *);
|
||||
|
||||
|
||||
4
tree.c
4
tree.c
@@ -153,10 +153,8 @@ static void track_tree_refs(struct tree *item)
|
||||
/* Count how many entries there are.. */
|
||||
desc.buf = item->buffer;
|
||||
desc.size = item->size;
|
||||
while (desc.size) {
|
||||
while (tree_entry(&desc, &entry))
|
||||
n_refs++;
|
||||
update_tree_entry(&desc);
|
||||
}
|
||||
|
||||
/* Allocate object refs and walk it again.. */
|
||||
i = 0;
|
||||
|
||||
Reference in New Issue
Block a user