summaryrefslogtreecommitdiff
path: root/builtin
diff options
context:
space:
mode:
Diffstat (limited to 'builtin')
-rw-r--r--builtin/add.c10
-rw-r--r--builtin/annotate.c12
-rw-r--r--builtin/apply.c192
-rw-r--r--builtin/blame.c980
-rw-r--r--builtin/branch.c111
-rw-r--r--builtin/cat-file.c5
-rw-r--r--builtin/checkout-index.c6
-rw-r--r--builtin/checkout.c64
-rw-r--r--builtin/clean.c19
-rw-r--r--builtin/clone.c71
-rw-r--r--builtin/commit-tree.c4
-rw-r--r--builtin/commit.c389
-rw-r--r--builtin/config.c85
-rw-r--r--builtin/count-objects.c101
-rw-r--r--builtin/describe.c14
-rw-r--r--builtin/diff-tree.c12
-rw-r--r--builtin/diff.c1
-rw-r--r--builtin/fast-export.c354
-rw-r--r--builtin/fetch.c88
-rw-r--r--builtin/fmt-merge-msg.c24
-rw-r--r--builtin/for-each-ref.c46
-rw-r--r--builtin/fsck.c18
-rw-r--r--builtin/gc.c79
-rw-r--r--builtin/get-tar-commit-id.c5
-rw-r--r--builtin/grep.c15
-rw-r--r--builtin/hash-object.c103
-rw-r--r--builtin/help.c4
-rw-r--r--builtin/index-pack.c114
-rw-r--r--builtin/init-db.c35
-rw-r--r--builtin/interpret-trailers.c44
-rw-r--r--builtin/log.c85
-rw-r--r--builtin/ls-files.c2
-rw-r--r--builtin/ls-remote.c2
-rw-r--r--builtin/mailinfo.c24
-rw-r--r--builtin/mailsplit.c16
-rw-r--r--builtin/merge-tree.c18
-rw-r--r--builtin/merge.c60
-rw-r--r--builtin/mv.c184
-rw-r--r--builtin/name-rev.c5
-rw-r--r--builtin/notes.c13
-rw-r--r--builtin/pack-objects.c101
-rw-r--r--builtin/patch-id.c74
-rw-r--r--builtin/prune-packed.c68
-rw-r--r--builtin/prune.c89
-rw-r--r--builtin/push.c21
-rw-r--r--builtin/read-tree.c19
-rw-r--r--builtin/receive-pack.c472
-rw-r--r--builtin/reflog.c8
-rw-r--r--builtin/remote-ext.c13
-rw-r--r--builtin/remote.c75
-rw-r--r--builtin/repack.c48
-rw-r--r--builtin/replace.c377
-rw-r--r--builtin/rerere.c2
-rw-r--r--builtin/reset.c18
-rw-r--r--builtin/rev-list.c5
-rw-r--r--builtin/rev-parse.c22
-rw-r--r--builtin/rm.c11
-rw-r--r--builtin/send-pack.c31
-rw-r--r--builtin/show-branch.c25
-rw-r--r--builtin/symbolic-ref.c2
-rw-r--r--builtin/tag.c186
-rw-r--r--builtin/unpack-objects.c14
-rw-r--r--builtin/update-index.c39
-rw-r--r--builtin/update-ref.c457
-rw-r--r--builtin/verify-commit.c93
-rw-r--r--builtin/verify-pack.c10
66 files changed, 3811 insertions, 1883 deletions
diff --git a/builtin/add.c b/builtin/add.c
index 459208a326..ae6d3e262b 100644
--- a/builtin/add.c
+++ b/builtin/add.c
@@ -5,6 +5,7 @@
*/
#include "cache.h"
#include "builtin.h"
+#include "lockfile.h"
#include "dir.h"
#include "pathspec.h"
#include "exec_cmd.h"
@@ -180,7 +181,7 @@ static int edit_patch(int argc, const char **argv, const char *prefix)
char *file = git_pathdup("ADD_EDIT.patch");
const char *apply_argv[] = { "apply", "--recount", "--cached",
NULL, NULL };
- struct child_process child;
+ struct child_process child = CHILD_PROCESS_INIT;
struct rev_info rev;
int out;
struct stat st;
@@ -214,7 +215,6 @@ static int edit_patch(int argc, const char **argv, const char *prefix)
if (!st.st_size)
die(_("Empty patch. Aborted."));
- memset(&child, 0, sizeof(child));
child.git_cmd = 1;
child.argv = apply_argv;
if (run_command(&child))
@@ -299,7 +299,6 @@ static int add_files(struct dir_struct *dir, int flags)
int cmd_add(int argc, const char **argv, const char *prefix)
{
int exit_status = 0;
- int newfd;
struct pathspec pathspec;
struct dir_struct dir;
int flags;
@@ -345,7 +344,7 @@ int cmd_add(int argc, const char **argv, const char *prefix)
add_new_files = !take_worktree_changes && !refresh_only;
require_pathspec = !take_worktree_changes;
- newfd = hold_locked_index(&lock_file, 1);
+ hold_locked_index(&lock_file, 1);
flags = ((verbose ? ADD_CACHE_VERBOSE : 0) |
(show_only ? ADD_CACHE_PRETEND : 0) |
@@ -443,8 +442,7 @@ int cmd_add(int argc, const char **argv, const char *prefix)
finish:
if (active_cache_changed) {
- if (write_cache(newfd, active_cache, active_nr) ||
- commit_locked_index(&lock_file))
+ if (write_locked_index(&the_index, &lock_file, COMMIT_LOCK))
die(_("Unable to write new index file"));
}
diff --git a/builtin/annotate.c b/builtin/annotate.c
index fc43eed36b..da413ae0d1 100644
--- a/builtin/annotate.c
+++ b/builtin/annotate.c
@@ -5,20 +5,18 @@
*/
#include "git-compat-util.h"
#include "builtin.h"
+#include "argv-array.h"
int cmd_annotate(int argc, const char **argv, const char *prefix)
{
- const char **nargv;
+ struct argv_array args = ARGV_ARRAY_INIT;
int i;
- nargv = xmalloc(sizeof(char *) * (argc + 2));
- nargv[0] = "annotate";
- nargv[1] = "-c";
+ argv_array_pushl(&args, "annotate", "-c", NULL);
for (i = 1; i < argc; i++) {
- nargv[i+1] = argv[i];
+ argv_array_push(&args, argv[i]);
}
- nargv[argc + 1] = NULL;
- return cmd_blame(argc + 1, nargv, prefix);
+ return cmd_blame(args.argc, args.argv, prefix);
}
diff --git a/builtin/apply.c b/builtin/apply.c
index 87439fad11..6696ea4c3f 100644
--- a/builtin/apply.c
+++ b/builtin/apply.c
@@ -7,6 +7,7 @@
*
*/
#include "cache.h"
+#include "lockfile.h"
#include "cache-tree.h"
#include "quote.h"
#include "blob.h"
@@ -300,11 +301,13 @@ static int fuzzy_matchlines(const char *s1, size_t n1,
while ((*last2 == '\r') || (*last2 == '\n'))
last2--;
- /* skip leading whitespace */
- while (isspace(*s1) && (s1 <= last1))
- s1++;
- while (isspace(*s2) && (s2 <= last2))
- s2++;
+ /* skip leading whitespaces, if both begin with whitespace */
+ if (s1 <= last1 && s2 <= last2 && isspace(*s1) && isspace(*s2)) {
+ while (isspace(*s1) && (s1 <= last1))
+ s1++;
+ while (isspace(*s2) && (s2 <= last2))
+ s2++;
+ }
/* early return if both lines are empty */
if ((s1 > last1) && (s2 > last2))
return 1;
@@ -433,7 +436,7 @@ static unsigned long linelen(const char *buffer, unsigned long size)
static int is_dev_null(const char *str)
{
- return !memcmp("/dev/null", str, 9) && isspace(str[9]);
+ return skip_prefix(str, "/dev/null", &str) && isspace(*str);
}
#define TERM_SPACE 1
@@ -1073,7 +1076,7 @@ static int gitdiff_index(const char *line, struct patch *patch)
line = ptr + 2;
ptr = strchr(line, ' ');
- eol = strchr(line, '\n');
+ eol = strchrnul(line, '\n');
if (!ptr || eol < ptr)
ptr = eol;
@@ -1279,9 +1282,7 @@ static int parse_git_header(const char *line, int len, unsigned int size, struct
*/
patch->def_name = git_header_name(line, len);
if (patch->def_name && root) {
- char *s = xmalloc(root_len + strlen(patch->def_name) + 1);
- strcpy(s, root);
- strcpy(s + root_len, patch->def_name);
+ char *s = xstrfmt("%s%s", root, patch->def_name);
free(patch->def_name);
patch->def_name = s;
}
@@ -1920,6 +1921,66 @@ static int parse_binary(char *buffer, unsigned long size, struct patch *patch)
return used;
}
+static void prefix_one(char **name)
+{
+ char *old_name = *name;
+ if (!old_name)
+ return;
+ *name = xstrdup(prefix_filename(prefix, prefix_length, *name));
+ free(old_name);
+}
+
+static void prefix_patch(struct patch *p)
+{
+ if (!prefix || p->is_toplevel_relative)
+ return;
+ prefix_one(&p->new_name);
+ prefix_one(&p->old_name);
+}
+
+/*
+ * include/exclude
+ */
+
+static struct string_list limit_by_name;
+static int has_include;
+static void add_name_limit(const char *name, int exclude)
+{
+ struct string_list_item *it;
+
+ it = string_list_append(&limit_by_name, name);
+ it->util = exclude ? NULL : (void *) 1;
+}
+
+static int use_patch(struct patch *p)
+{
+ const char *pathname = p->new_name ? p->new_name : p->old_name;
+ int i;
+
+ /* Paths outside are not touched regardless of "--include" */
+ if (0 < prefix_length) {
+ int pathlen = strlen(pathname);
+ if (pathlen <= prefix_length ||
+ memcmp(prefix, pathname, prefix_length))
+ return 0;
+ }
+
+ /* See if it matches any of exclude/include rule */
+ for (i = 0; i < limit_by_name.nr; i++) {
+ struct string_list_item *it = &limit_by_name.items[i];
+ if (!wildmatch(it->string, pathname, 0, NULL))
+ return (it->util != NULL);
+ }
+
+ /*
+ * If we had any include, a path that does not match any rule is
+ * not used. Otherwise, we saw bunch of exclude rules (or none)
+ * and such a path is used.
+ */
+ return !has_include;
+}
+
+
/*
* Read the patch text in "buffer" that extends for "size" bytes; stop
* reading after seeing a single patch (i.e. changes to a single file).
@@ -1935,9 +1996,14 @@ static int parse_chunk(char *buffer, unsigned long size, struct patch *patch)
if (offset < 0)
return offset;
- patch->ws_rule = whitespace_rule(patch->new_name
- ? patch->new_name
- : patch->old_name);
+ prefix_patch(patch);
+
+ if (!use_patch(patch))
+ patch->ws_rule = 0;
+ else
+ patch->ws_rule = whitespace_rule(patch->new_name
+ ? patch->new_name
+ : patch->old_name);
patchsize = parse_single_patch(buffer + offset + hdrsize,
size - offset - hdrsize, patch);
@@ -2561,7 +2627,7 @@ static void update_image(struct image *img,
* NOTE: this knows that we never call remove_first_line()
* on anything other than pre/post image.
*/
- img->line = xrealloc(img->line, nr * sizeof(*img->line));
+ REALLOC_ARRAY(img->line, nr);
img->line_allocated = img->line;
}
if (preimage_limit != postimage->nr)
@@ -2867,9 +2933,7 @@ static int apply_binary_fragment(struct image *img, struct patch *patch)
case BINARY_LITERAL_DEFLATED:
clear_image(img);
img->len = fragment->size;
- img->buf = xmalloc(img->len+1);
- memcpy(img->buf, fragment->patch, img->len);
- img->buf[img->len] = '\0';
+ img->buf = xmemdupz(fragment->patch, img->len);
return 0;
}
return -1;
@@ -3084,13 +3148,15 @@ static void prepare_fn_table(struct patch *patch)
}
}
-static int checkout_target(struct cache_entry *ce, struct stat *st)
+static int checkout_target(struct index_state *istate,
+ struct cache_entry *ce, struct stat *st)
{
struct checkout costate;
memset(&costate, 0, sizeof(costate));
costate.base_dir = "";
costate.refresh_cache = 1;
+ costate.istate = istate;
if (checkout_entry(ce, &costate, NULL) || lstat(ce->name, st))
return error(_("cannot checkout %s"), ce->name);
return 0;
@@ -3257,7 +3323,7 @@ static int load_current(struct image *image, struct patch *patch)
if (lstat(name, &st)) {
if (errno != ENOENT)
return error(_("%s: %s"), name, strerror(errno));
- if (checkout_target(ce, &st))
+ if (checkout_target(&the_index, ce, &st))
return -1;
}
if (verify_index_match(ce, &st))
@@ -3411,7 +3477,7 @@ static int check_preimage(struct patch *patch, struct cache_entry **ce, struct s
}
*ce = active_cache[pos];
if (stat_ret < 0) {
- if (checkout_target(*ce, st))
+ if (checkout_target(&the_index, *ce, st))
return -1;
}
if (!cached && verify_index_match(*ce, st))
@@ -3644,7 +3710,7 @@ static void build_fake_ancestor(struct patch *list, const char *filename)
{
struct patch *patch;
struct index_state result = { NULL };
- int fd;
+ static struct lock_file lock;
/* Once we start supporting the reverse patch, it may be
* worth showing the new sha1 prefix, but until then...
@@ -3682,8 +3748,8 @@ static void build_fake_ancestor(struct patch *list, const char *filename)
die ("Could not add %s to temporary index", name);
}
- fd = open(filename, O_WRONLY | O_CREAT, 0666);
- if (fd < 0 || write_index(&result, fd) || close(fd))
+ hold_lock_file_for_update(&lock, filename, LOCK_DIE_ON_ERROR);
+ if (write_locked_index(&result, &lock, COMMIT_LOCK))
die ("Could not write temporary index to %s", filename);
discard_index(&result);
@@ -3845,9 +3911,10 @@ static void add_index_file(const char *path, unsigned mode, void *buf, unsigned
ce->ce_flags = create_ce_flags(0);
ce->ce_namelen = namelen;
if (S_ISGITLINK(mode)) {
- const char *s = buf;
+ const char *s;
- if (get_sha1_hex(s + strlen("Subproject commit "), ce->sha1))
+ if (!skip_prefix(buf, "Subproject commit ", &s) ||
+ get_sha1_hex(s, ce->sha1))
die(_("corrupt patch for submodule %s"), path);
} else {
if (!cached) {
@@ -4126,64 +4193,6 @@ static int write_out_results(struct patch *list)
static struct lock_file lock_file;
-static struct string_list limit_by_name;
-static int has_include;
-static void add_name_limit(const char *name, int exclude)
-{
- struct string_list_item *it;
-
- it = string_list_append(&limit_by_name, name);
- it->util = exclude ? NULL : (void *) 1;
-}
-
-static int use_patch(struct patch *p)
-{
- const char *pathname = p->new_name ? p->new_name : p->old_name;
- int i;
-
- /* Paths outside are not touched regardless of "--include" */
- if (0 < prefix_length) {
- int pathlen = strlen(pathname);
- if (pathlen <= prefix_length ||
- memcmp(prefix, pathname, prefix_length))
- return 0;
- }
-
- /* See if it matches any of exclude/include rule */
- for (i = 0; i < limit_by_name.nr; i++) {
- struct string_list_item *it = &limit_by_name.items[i];
- if (!wildmatch(it->string, pathname, 0, NULL))
- return (it->util != NULL);
- }
-
- /*
- * If we had any include, a path that does not match any rule is
- * not used. Otherwise, we saw bunch of exclude rules (or none)
- * and such a path is used.
- */
- return !has_include;
-}
-
-
-static void prefix_one(char **name)
-{
- char *old_name = *name;
- if (!old_name)
- return;
- *name = xstrdup(prefix_filename(prefix, prefix_length, *name));
- free(old_name);
-}
-
-static void prefix_patches(struct patch *p)
-{
- if (!prefix || p->is_toplevel_relative)
- return;
- for ( ; p; p = p->next) {
- prefix_one(&p->new_name);
- prefix_one(&p->old_name);
- }
-}
-
#define INACCURATE_EOF (1<<0)
#define RECOUNT (1<<1)
@@ -4209,8 +4218,6 @@ static int apply_patch(int fd, const char *filename, int options)
break;
if (apply_in_reverse)
reverse_patches(patch);
- if (prefix)
- prefix_patches(patch);
if (use_patch(patch)) {
patch_stats(patch);
*listp = patch;
@@ -4268,13 +4275,11 @@ static int apply_patch(int fd, const char *filename, int options)
return 0;
}
-static int git_apply_config(const char *var, const char *value, void *cb)
+static void git_apply_config(void)
{
- if (!strcmp(var, "apply.whitespace"))
- return git_config_string(&apply_default_whitespace, var, value);
- else if (!strcmp(var, "apply.ignorewhitespace"))
- return git_config_string(&apply_default_ignorewhitespace, var, value);
- return git_default_config(var, value, cb);
+ git_config_get_string_const("apply.whitespace", &apply_default_whitespace);
+ git_config_get_string_const("apply.ignorewhitespace", &apply_default_ignorewhitespace);
+ git_config(git_default_config, NULL);
}
static int option_parse_exclude(const struct option *opt,
@@ -4422,7 +4427,7 @@ int cmd_apply(int argc, const char **argv, const char *prefix_)
prefix = prefix_;
prefix_length = prefix ? strlen(prefix) : 0;
- git_config(git_apply_config, NULL);
+ git_apply_config();
if (apply_default_whitespace)
parse_whitespace_option(apply_default_whitespace);
if (apply_default_ignorewhitespace)
@@ -4501,8 +4506,7 @@ int cmd_apply(int argc, const char **argv, const char *prefix_)
}
if (update_index) {
- if (write_cache(newfd, active_cache, active_nr) ||
- commit_locked_index(&lock_file))
+ if (write_locked_index(&the_index, &lock_file, COMMIT_LOCK))
die(_("Unable to write new index file"));
}
diff --git a/builtin/blame.c b/builtin/blame.c
index 88cb799727..303e217ae9 100644
--- a/builtin/blame.c
+++ b/builtin/blame.c
@@ -1,7 +1,8 @@
/*
* Blame
*
- * Copyright (c) 2006, Junio C Hamano
+ * Copyright (c) 2006, 2014 by its authors
+ * See COPYING for licensing conditions
*/
#include "cache.h"
@@ -18,7 +19,9 @@
#include "cache-tree.h"
#include "string-list.h"
#include "mailmap.h"
+#include "mergesort.h"
#include "parse-options.h"
+#include "prio-queue.h"
#include "utf8.h"
#include "userdiff.h"
#include "line-range.h"
@@ -83,11 +86,42 @@ static unsigned blame_copy_score;
*/
struct origin {
int refcnt;
+ /* Record preceding blame record for this blob */
struct origin *previous;
+ /* origins are put in a list linked via `next' hanging off the
+ * corresponding commit's util field in order to make finding
+ * them fast. The presence in this chain does not count
+ * towards the origin's reference count. It is tempting to
+ * let it count as long as the commit is pending examination,
+ * but even under circumstances where the commit will be
+ * present multiple times in the priority queue of unexamined
+ * commits, processing the first instance will not leave any
+ * work requiring the origin data for the second instance. An
+ * interspersed commit changing that would have to be
+ * preexisting with a different ancestry and with the same
+ * commit date in order to wedge itself between two instances
+ * of the same commit in the priority queue _and_ produce
+ * blame entries relevant for it. While we don't want to let
+ * us get tripped up by this case, it certainly does not seem
+ * worth optimizing for.
+ */
+ struct origin *next;
struct commit *commit;
+ /* `suspects' contains blame entries that may be attributed to
+ * this origin's commit or to parent commits. When a commit
+ * is being processed, all suspects will be moved, either by
+ * assigning them to an origin in a different commit, or by
+ * shipping them to the scoreboard's ent list because they
+ * cannot be attributed to a different commit.
+ */
+ struct blame_entry *suspects;
mmfile_t file;
unsigned char blob_sha1[20];
unsigned mode;
+ /* guilty gets set when shipping any suspects to the final
+ * blame list instead of other commits
+ */
+ char guilty;
char path[FLEX_ARRAY];
};
@@ -176,10 +210,22 @@ static inline struct origin *origin_incref(struct origin *o)
static void origin_decref(struct origin *o)
{
if (o && --o->refcnt <= 0) {
+ struct origin *p, *l = NULL;
if (o->previous)
origin_decref(o->previous);
free(o->file.ptr);
- free(o);
+ /* Should be present exactly once in commit chain */
+ for (p = o->commit->util; p; l = p, p = p->next) {
+ if (p == o) {
+ if (l)
+ l->next = p->next;
+ else
+ o->commit->util = p->next;
+ free(o);
+ return;
+ }
+ }
+ die("internal error in blame::origin_decref");
}
}
@@ -193,8 +239,12 @@ static void drop_origin_blob(struct origin *o)
/*
* Each group of lines is described by a blame_entry; it can be split
- * as we pass blame to the parents. They form a linked list in the
- * scoreboard structure, sorted by the target line number.
+ * as we pass blame to the parents. They are arranged in linked lists
+ * kept as `suspects' of some unprocessed origin, or entered (when the
+ * blame origin has been finalized) into the scoreboard structure.
+ * While the scoreboard structure is only sorted at the end of
+ * processing (according to final image line number), the lists
+ * attached to an origin are sorted by the target line number.
*/
struct blame_entry {
struct blame_entry *next;
@@ -210,15 +260,6 @@ struct blame_entry {
/* the commit that introduced this group into the final image */
struct origin *suspect;
- /* true if the suspect is truly guilty; false while we have not
- * checked if the group came from one of its parents.
- */
- char guilty;
-
- /* true if the entry has been scanned for copies in the current parent
- */
- char scanned;