summaryrefslogtreecommitdiff
path: root/builtin
diff options
context:
space:
mode:
Diffstat (limited to 'builtin')
-rw-r--r--builtin/add.c2
-rw-r--r--builtin/apply.c63
-rw-r--r--builtin/branch.c8
-rw-r--r--builtin/clean.c154
-rw-r--r--builtin/clone.c6
-rw-r--r--builtin/commit.c4
-rw-r--r--builtin/fmt-merge-msg.c21
-rw-r--r--builtin/grep.c4
-rw-r--r--builtin/help.c18
-rw-r--r--builtin/index-pack.c9
-rw-r--r--builtin/merge-index.c4
-rw-r--r--builtin/merge-tree.c92
-rw-r--r--builtin/merge.c6
-rw-r--r--builtin/pack-redundant.c6
-rw-r--r--builtin/prune.c4
-rw-r--r--builtin/shortlog.c5
-rw-r--r--builtin/update-index.c2
17 files changed, 266 insertions, 142 deletions
diff --git a/builtin/add.c b/builtin/add.c
index e664100c71..632594768d 100644
--- a/builtin/add.c
+++ b/builtin/add.c
@@ -16,7 +16,7 @@
#include "bulk-checkin.h"
static const char * const builtin_add_usage[] = {
- N_("git add [options] [--] <filepattern>..."),
+ N_("git add [options] [--] <pathspec>..."),
NULL
};
static int patch_interactive, add_interactive, edit_interactive;
diff --git a/builtin/apply.c b/builtin/apply.c
index 156b3ce3b7..080ce2ea3e 100644
--- a/builtin/apply.c
+++ b/builtin/apply.c
@@ -1041,15 +1041,17 @@ static int gitdiff_renamedst(const char *line, struct patch *patch)
static int gitdiff_similarity(const char *line, struct patch *patch)
{
- if ((patch->score = strtoul(line, NULL, 10)) == ULONG_MAX)
- patch->score = 0;
+ unsigned long val = strtoul(line, NULL, 10);
+ if (val <= 100)
+ patch->score = val;
return 0;
}
static int gitdiff_dissimilarity(const char *line, struct patch *patch)
{
- if ((patch->score = strtoul(line, NULL, 10)) == ULONG_MAX)
- patch->score = 0;
+ unsigned long val = strtoul(line, NULL, 10);
+ if (val <= 100)
+ patch->score = val;
return 0;
}
@@ -2095,7 +2097,7 @@ static void update_pre_post_images(struct image *preimage,
char *buf,
size_t len, size_t postlen)
{
- int i, ctx;
+ int i, ctx, reduced;
char *new, *old, *fixed;
struct image fixed_preimage;
@@ -2105,8 +2107,10 @@ static void update_pre_post_images(struct image *preimage,
* free "oldlines".
*/
prepare_image(&fixed_preimage, buf, len, 1);
- assert(fixed_preimage.nr == preimage->nr);
- for (i = 0; i < preimage->nr; i++)
+ assert(postlen
+ ? fixed_preimage.nr == preimage->nr
+ : fixed_preimage.nr <= preimage->nr);
+ for (i = 0; i < fixed_preimage.nr; i++)
fixed_preimage.line[i].flag = preimage->line[i].flag;
free(preimage->line_allocated);
*preimage = fixed_preimage;
@@ -2126,7 +2130,8 @@ static void update_pre_post_images(struct image *preimage,
else
new = old;
fixed = preimage->buf;
- for (i = ctx = 0; i < postimage->nr; i++) {
+
+ for (i = reduced = ctx = 0; i < postimage->nr; i++) {
size_t len = postimage->line[i].len;
if (!(postimage->line[i].flag & LINE_COMMON)) {
/* an added line -- no counterparts in preimage */
@@ -2145,8 +2150,15 @@ static void update_pre_post_images(struct image *preimage,
fixed += preimage->line[ctx].len;
ctx++;
}
- if (preimage->nr <= ctx)
- die(_("oops"));
+
+ /*
+ * preimage is expected to run out, if the caller
+ * fixed addition of trailing blank lines.
+ */
+ if (preimage->nr <= ctx) {
+ reduced++;
+ continue;
+ }
/* and copy it in, while fixing the line length */
len = preimage->line[ctx].len;
@@ -2159,6 +2171,7 @@ static void update_pre_post_images(struct image *preimage,
/* Fix the length of the whole thing */
postimage->len = new - postimage->buf;
+ postimage->nr -= reduced;
}
static int match_fragment(struct image *img,
@@ -3598,7 +3611,6 @@ static void build_fake_ancestor(struct patch *list, const char *filename)
* worth showing the new sha1 prefix, but until then...
*/
for (patch = list; patch; patch = patch->next) {
- const unsigned char *sha1_ptr;
unsigned char sha1[20];
struct cache_entry *ce;
const char *name;
@@ -3606,20 +3618,23 @@ static void build_fake_ancestor(struct patch *list, const char *filename)
name = patch->old_name ? patch->old_name : patch->new_name;
if (0 < patch->is_new)
continue;
- else if (get_sha1_blob(patch->old_sha1_prefix, sha1))
- /* git diff has no index line for mode/type changes */
- if (!patch->lines_added && !patch->lines_deleted) {
- if (get_current_sha1(patch->old_name, sha1))
- die("mode change for %s, which is not "
- "in current HEAD", name);
- sha1_ptr = sha1;
- } else
- die("sha1 information is lacking or useless "
- "(%s).", name);
- else
- sha1_ptr = sha1;
- ce = make_cache_entry(patch->old_mode, sha1_ptr, name, 0, 0);
+ if (S_ISGITLINK(patch->old_mode)) {
+ if (get_sha1_hex(patch->old_sha1_prefix, sha1))
+ die("submoule change for %s without full index name",
+ name);
+ } else if (!get_sha1_blob(patch->old_sha1_prefix, sha1)) {
+ ; /* ok */
+ } else if (!patch->lines_added && !patch->lines_deleted) {
+ /* mode-only change: update the current */
+ if (get_current_sha1(patch->old_name, sha1))
+ die("mode change for %s, which is not "
+ "in current HEAD", name);
+ } else
+ die("sha1 information is lacking or useless "
+ "(%s).", name);
+
+ ce = make_cache_entry(patch->old_mode, sha1, name, 0, 0);
if (!ce)
die(_("make_cache_entry failed for path '%s'"), name);
if (add_index_entry(&result, ce, ADD_CACHE_OK_TO_ADD))
diff --git a/builtin/branch.c b/builtin/branch.c
index 1ec9c02612..947c84be2d 100644
--- a/builtin/branch.c
+++ b/builtin/branch.c
@@ -850,11 +850,11 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
const char *branch_name;
struct strbuf branch_ref = STRBUF_INIT;
- if (detached)
- die("Cannot give description to detached HEAD");
- if (!argc)
+ if (!argc) {
+ if (detached)
+ die("Cannot give description to detached HEAD");
branch_name = head;
- else if (argc == 1)
+ } else if (argc == 1)
branch_name = argv[0];
else
usage_with_options(builtin_branch_usage, options);
diff --git a/builtin/clean.c b/builtin/clean.c
index 69c1cda906..f4b760bf3d 100644
--- a/builtin/clean.c
+++ b/builtin/clean.c
@@ -10,6 +10,7 @@
#include "cache.h"
#include "dir.h"
#include "parse-options.h"
+#include "refs.h"
#include "string-list.h"
#include "quote.h"
@@ -20,6 +21,12 @@ static const char *const builtin_clean_usage[] = {
NULL
};
+static const char *msg_remove = N_("Removing %s\n");
+static const char *msg_would_remove = N_("Would remove %s\n");
+static const char *msg_skip_git_dir = N_("Skipping repository %s\n");
+static const char *msg_would_skip_git_dir = N_("Would skip repository %s\n");
+static const char *msg_warn_remove_failed = N_("failed to remove %s");
+
static int git_clean_config(const char *var, const char *value, void *cb)
{
if (!strcmp(var, "clean.requireforce"))
@@ -34,11 +41,112 @@ static int exclude_cb(const struct option *opt, const char *arg, int unset)
return 0;
}
+static int remove_dirs(struct strbuf *path, const char *prefix, int force_flag,
+ int dry_run, int quiet, int *dir_gone)
+{
+ DIR *dir;
+ struct strbuf quoted = STRBUF_INIT;
+ struct dirent *e;
+ int res = 0, ret = 0, gone = 1, original_len = path->len, len, i;
+ unsigned char submodule_head[20];
+ struct string_list dels = STRING_LIST_INIT_DUP;
+
+ *dir_gone = 1;
+
+ if ((force_flag & REMOVE_DIR_KEEP_NESTED_GIT) &&
+ !resolve_gitlink_ref(path->buf, "HEAD", submodule_head)) {
+ if (!quiet) {
+ quote_path_relative(path->buf, strlen(path->buf), &quoted, prefix);
+ printf(dry_run ? _(msg_would_skip_git_dir) : _(msg_skip_git_dir),
+ quoted.buf);
+ }
+
+ *dir_gone = 0;
+ return 0;
+ }
+
+ dir = opendir(path->buf);
+ if (!dir) {
+ /* an empty dir could be removed even if it is unreadble */
+ res = dry_run ? 0 : rmdir(path->buf);
+ if (res) {
+ quote_path_relative(path->buf, strlen(path->buf), &quoted, prefix);
+ warning(_(msg_warn_remove_failed), quoted.buf);
+ *dir_gone = 0;
+ }
+ return res;
+ }
+
+ if (path->buf[original_len - 1] != '/')
+ strbuf_addch(path, '/');
+
+ len = path->len;
+ while ((e = readdir(dir)) != NULL) {
+ struct stat st;
+ if (is_dot_or_dotdot(e->d_name))
+ continue;
+
+ strbuf_setlen(path, len);
+ strbuf_addstr(path, e->d_name);
+ if (lstat(path->buf, &st))
+ ; /* fall thru */
+ else if (S_ISDIR(st.st_mode)) {
+ if (remove_dirs(path, prefix, force_flag, dry_run, quiet, &gone))
+ ret = 1;
+ if (gone) {
+ quote_path_relative(path->buf, strlen(path->buf), &quoted, prefix);
+ string_list_append(&dels, quoted.buf);
+ } else
+ *dir_gone = 0;
+ continue;
+ } else {
+ res = dry_run ? 0 : unlink(path->buf);
+ if (!res) {
+ quote_path_relative(path->buf, strlen(path->buf), &quoted, prefix);
+ string_list_append(&dels, quoted.buf);
+ } else {
+ quote_path_relative(path->buf, strlen(path->buf), &quoted, prefix);
+ warning(_(msg_warn_remove_failed), quoted.buf);
+ *dir_gone = 0;
+ ret = 1;
+ }
+ continue;
+ }
+
+ /* path too long, stat fails, or non-directory still exists */
+ *dir_gone = 0;
+ ret = 1;
+ break;
+ }
+ closedir(dir);
+
+ strbuf_setlen(path, original_len);
+
+ if (*dir_gone) {
+ res = dry_run ? 0 : rmdir(path->buf);
+ if (!res)
+ *dir_gone = 1;
+ else {
+ quote_path_relative(path->buf, strlen(path->buf), &quoted, prefix);
+ warning(_(msg_warn_remove_failed), quoted.buf);
+ *dir_gone = 0;
+ ret = 1;
+ }
+ }
+
+ if (!*dir_gone && !quiet) {
+ for (i = 0; i < dels.nr; i++)
+ printf(dry_run ? _(msg_would_remove) : _(msg_remove), dels.items[i].string);
+ }
+ string_list_clear(&dels, 0);
+ return ret;
+}
+
int cmd_clean(int argc, const char **argv, const char *prefix)
{
- int i;
- int show_only = 0, remove_directories = 0, quiet = 0, ignored = 0;
- int ignored_only = 0, config_set = 0, errors = 0;
+ int i, res;
+ int dry_run = 0, remove_directories = 0, quiet = 0, ignored = 0;
+ int ignored_only = 0, config_set = 0, errors = 0, gone = 1;
int rm_flags = REMOVE_DIR_KEEP_NESTED_GIT;
struct strbuf directory = STRBUF_INIT;
struct dir_struct dir;
@@ -49,7 +157,7 @@ int cmd_clean(int argc, const char **argv, const char *prefix)
char *seen = NULL;
struct option options[] = {
OPT__QUIET(&quiet, N_("do not print names of files removed")),
- OPT__DRY_RUN(&show_only, N_("dry run")),
+ OPT__DRY_RUN(&dry_run, N_("dry run")),
OPT__FORCE(&force, N_("force")),
OPT_BOOLEAN('d', NULL, &remove_directories,
N_("remove whole directories")),
@@ -77,7 +185,7 @@ int cmd_clean(int argc, const char **argv, const char *prefix)
if (ignored && ignored_only)
die(_("-x and -X cannot be used together"));
- if (!show_only && !force) {
+ if (!dry_run && !force) {
if (config_set)
die(_("clean.requireForce set to true and neither -n nor -f given; "
"refusing to clean"));
@@ -149,38 +257,26 @@ int cmd_clean(int argc, const char **argv, const char *prefix)
if (S_ISDIR(st.st_mode)) {
strbuf_addstr(&directory, ent->name);
- qname = quote_path_relative(directory.buf, directory.len, &buf, prefix);
- if (show_only && (remove_directories ||
- (matches == MATCHED_EXACTLY))) {
- printf(_("Would remove %s\n"), qname);
- } else if (remove_directories ||
- (matches == MATCHED_EXACTLY)) {
- if (!quiet)
- printf(_("Removing %s\n"), qname);
- if (remove_dir_recursively(&directory,
- rm_flags) != 0) {
- warning(_("failed to remove %s"), qname);
+ if (remove_directories || (matches == MATCHED_EXACTLY)) {
+ if (remove_dirs(&directory, prefix, rm_flags, dry_run, quiet, &gone))
errors++;
+ if (gone && !quiet) {
+ qname = quote_path_relative(directory.buf, directory.len, &buf, prefix);
+ printf(dry_run ? _(msg_would_remove) : _(msg_remove), qname);
}
- } else if (show_only) {
- printf(_("Would not remove %s\n"), qname);
- } else {
- printf(_("Not removing %s\n"), qname);
}
strbuf_reset(&directory);
} else {
if (pathspec && !matches)
continue;
- qname = quote_path_relative(ent->name, -1, &buf, prefix);
- if (show_only) {
- printf(_("Would remove %s\n"), qname);
- continue;
- } else if (!quiet) {
- printf(_("Removing %s\n"), qname);
- }
- if (unlink(ent->name) != 0) {
- warning(_("failed to remove %s"), qname);
+ res = dry_run ? 0 : unlink(ent->name);
+ if (res) {
+ qname = quote_path_relative(ent->name, -1, &buf, prefix);
+ warning(_(msg_warn_remove_failed), qname);
errors++;
+ } else if (!quiet) {
+ qname = quote_path_relative(ent->name, -1, &buf, prefix);
+ printf(dry_run ? _(msg_would_remove) : _(msg_remove), qname);
}
}
}
diff --git a/builtin/clone.c b/builtin/clone.c
index ec2f75b4f3..36ec99db3f 100644
--- a/builtin/clone.c
+++ b/builtin/clone.c
@@ -704,6 +704,8 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
if (option_origin)
die(_("--bare and --origin %s options are incompatible."),
option_origin);
+ if (real_git_dir)
+ die(_("--bare and --separate-git-dir are incompatible."));
option_no_checkout = 1;
}
@@ -771,8 +773,10 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
die(_("could not create leading directories of '%s'"), git_dir);
set_git_dir_init(git_dir, real_git_dir, 0);
- if (real_git_dir)
+ if (real_git_dir) {
git_dir = real_git_dir;
+ junk_git_dir = real_git_dir;
+ }
if (0 <= option_verbosity) {
if (option_bare)
diff --git a/builtin/commit.c b/builtin/commit.c
index d6dd3df8b1..96684108e7 100644
--- a/builtin/commit.c
+++ b/builtin/commit.c
@@ -31,12 +31,12 @@
#include "sequencer.h"
static const char * const builtin_commit_usage[] = {
- N_("git commit [options] [--] <filepattern>..."),
+ N_("git commit [options] [--] <pathspec>..."),
NULL
};
static const char * const builtin_status_usage[] = {
- N_("git status [options] [--] <filepattern>..."),
+ N_("git status [options] [--] <pathspec>..."),
NULL
};
diff --git a/builtin/fmt-merge-msg.c b/builtin/fmt-merge-msg.c
index e2e27b2c40..d9af43c257 100644
--- a/builtin/fmt-merge-msg.c
+++ b/builtin/fmt-merge-msg.c
@@ -232,8 +232,9 @@ static void record_person(int which, struct string_list *people,
{
char *name_buf, *name, *name_end;
struct string_list_item *elem;
- const char *field = (which == 'a') ? "\nauthor " : "\ncommitter ";
+ const char *field;
+ field = (which == 'a') ? "\nauthor " : "\ncommitter ";
name = strstr(commit->buffer, field);
if (!name)
return;
@@ -323,7 +324,8 @@ static void add_people_info(struct strbuf *out,
static void shortlog(const char *name,
struct origin_data *origin_data,
struct commit *head,
- struct rev_info *rev, int limit,
+ struct rev_info *rev,
+ struct fmt_merge_msg_opts *opts,
struct strbuf *out)
{
int i, count = 0;
@@ -335,6 +337,7 @@ static void shortlog(const char *name,
int flags = UNINTERESTING | TREESAME | SEEN | SHOWN | ADDED;
struct strbuf sb = STRBUF_INIT;
const unsigned char *sha1 = origin_data->sha1;
+ int limit = opts->shortlog_len;
branch = deref_tag(parse_object(sha1), sha1_to_hex(sha1), 40);
if (!branch || branch->type != OBJ_COMMIT)
@@ -351,13 +354,15 @@ static void shortlog(const char *name,
if (commit->parents && commit->parents->next) {
/* do not list a merge but count committer */
- record_person('c', &committers, commit);
+ if (opts->credit_people)
+ record_person('c', &committers, commit);
continue;
}
- if (!count)
+ if (!count && opts->credit_people)
/* the 'tip' committer */
record_person('c', &committers, commit);
- record_person('a', &authors, commit);
+ if (opts->credit_people)
+ record_person('a', &authors, commit);
count++;
if (subjects.nr > limit)
continue;
@@ -372,7 +377,8 @@ static void shortlog(const char *name,
string_list_append(&subjects, strbuf_detach(&sb, NULL));
}
- add_people_info(out, &authors, &committers);
+ if (opts->credit_people)
+ add_people_info(out, &authors, &committers);
if (count > limit)
strbuf_addf(out, "\n* %s: (%d commits)\n", name, count);
else
@@ -635,7 +641,7 @@ int fmt_merge_msg(struct strbuf *in, struct strbuf *out,
for (i = 0; i < origins.nr; i++)
shortlog(origins.items[i].string,
origins.items[i].util,
- head, &rev, opts->shortlog_len, out);
+ head, &rev, opts, out);
}
strbuf_complete_line(out);
@@ -690,6 +696,7 @@ int cmd_fmt_merge_msg(int argc, const char **argv, const char *prefix)
memset(&opts, 0, sizeof(opts));
opts.add_title = !message;
+ opts.credit_people = 1;
opts.shortlog_len = shortlog_len;
ret = fmt_merge_msg(&input, &output, &opts);
diff --git a/builtin/grep.c b/builtin/grep.c
index 0e1b6c860e..e8f0f92cf7 100644
--- a/builtin/grep.c
+++ b/builtin/grep.c
@@ -820,9 +820,7 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
unsigned char sha1[20];
/* Is it a rev? */
if (!get_sha1(arg, sha1)) {
- struct object *object = parse_object(sha1);
- if (!object)
- die(_("bad object %s"), arg);
+ struct object *object = parse_object_or_die(sha1, arg);
add_object_array(object, arg, &list);
continue;
}
diff --git a/builtin/help.c b/builtin/help.c
index bd86253d83..6067a6134b 100644
--- a/builtin/help.c
+++ b/builtin/help.c
@@ -6,7 +6,6 @@
#include "cache.h"
#include "builtin.h"
#include "exec_cmd.h"
-#include "common-cmds.h"
#include "parse-options.h"
#include "run-command.h"
#include "column.h"
@@ -287,23 +286,6 @@ static int git_help_config(const char *var, const char *value, void *cb)
static struct cmdnames main_cmds, other_cmds;
-void list_common_cmds_help(void)
-{
- int i, longest = 0;
-
- for (i = 0; i < ARRAY_SIZE(common_cmds); i++) {
- if (longest < strlen(common_cmds[i].name))
- longest = strlen(common_cmds[i].name);
- }
-
- puts(_("The most commonly used git commands are:"));
- for (i = 0; i < ARRAY_SIZE(common_cmds); i++) {
- printf(" %s ", common_cmds[i].name);
- mput_char(' ', longest - strlen(common_cmds[i].name));
- puts(_(common_cmds[i].help));
- }
-}
-
static int is_git_command(const char *s)
{
return is_in_cmdlist(&main_cmds, s) ||
diff --git a/builtin/index-pack.c b/builtin/index-pack.c
index 43d364b8d5..ef62124aa4 100644
--- a/builtin/index-pack.c
+++ b/builtin/index-pack.c
@@ -1099,7 +1099,7 @@ static void conclude_pack(int fix_thin_pack, const char *curr_pack, unsigned cha
if (fix_thin_pack) {
struct sha1file *f;
unsigned char read_sha1[20], tail_sha1[20];
- char msg[48];
+ struct strbuf msg = STRBUF_INIT;
int nr_unresolved = nr_deltas - nr_resolved_deltas;
int nr_objects_initial = nr_objects;
if (nr_unresolved <= 0)
@@ -1109,9 +1109,10 @@ static void conclude_pack(int fix_thin_pack, const char *curr_pack, unsigned cha
* sizeof(*objects));
f = sha1fd(output_fd, curr_pack);
fix_unresolved_deltas(f, nr_unresolved);
- sprintf(msg, _("completed with %d local objects"),
- nr_objects - nr_objects_initial);
- stop_progress_msg(&progress, msg);
+ strbuf_addf(&msg, _("completed with %d local objects"),
+ nr_objects - nr_objects_initial);
+ stop_progress_msg(&progress, msg.buf);
+ strbuf_release(&msg);
sha1close(f, tail_sha1, 0);
hashcpy(read_sha1, pack_sha1);
fixup_pack_header_footer(output_fd, pack_sha1,
diff --git a/builtin/merge-index.c b/builtin/merge-index.c
index 2338832587..be5e514324 100644
--- a/builtin/merge-index.c
+++ b/builtin/merge-index.c
@@ -42,7 +42,7 @@ static int merge_entry(int pos, const char *path)
return found;
}
-static void merge_file(const char *path)
+static void merge_one_path(const char *path)
{
int pos = cache_name_pos(path, strlen(path));
@@ -102,7 +102,7 @@ int cmd_merge_index(int argc, const char **argv, const char *prefix)
}
die("git merge-index: unknown option %s", arg);
}
- merge_file(arg);
+ merge_one_path(arg);
}
if (err && !quiet)
die("merge program failed");
diff --git a/builtin/merge-tree.c b/builtin/merge-tree.c
index 897a563bc6..bc912e399e 100644
--- a/builtin/merge-tree.c
+++ b/builtin/merge-tree.c
@@ -3,17 +3,15 @@
#include "xdiff-interface.h"
#include "blob.h"
#include "exec_cmd.h"
-#include "merge-file.h"
+#include "merge-blobs.h"
static const char merge_tree_usage[] = "git merge-tree <base-tree> <branch1> <branch2>";
-static int resolve_directories = 1;
struct merge_list {
struct merge_list *next;
struct merge_list *link; /* other stages for this object */
- unsigned int stage : 2,
- flags : 30;
+ unsigned int stage : 2;
unsigned int mode;
const char *path;
struct blob *blob;
@@ -27,7 +25,7 @@ static void add_merge_entry(struct merge_list *entry)
merge_result_end = &entry->next;
}
-static void merge_trees(struct tree_desc t[3], const char *base);
+static void merge_trees_recursive(struct tree_desc t[3], const char *base, int df_conflict);
static const char *explanation(struct merge_list *entry)
{
@@ -76,7 +74,7 @@ static void *result(struct merge_list *entry, unsigned long *size)
their = NULL;
if (entry)
their = entry->blob;
- return merge_file(path, base, our, their, size);
+ return merge_blobs(path, base, our, their, size);
}
static void *origin(struct merge_list *entry, unsigned long *size)
@@ -174,17 +172,17 @@ static char *traverse_path(const struct traverse_info *info, const struct name_e
return make_traverse_path(path, info, n);
}
-static void resolve(const struct traverse_info *info, struct name_entry *branch1, struct name_entry *result)
+static void resolve(const struct traverse_info *info, struct name_entry *ours, struct name_entry *result)
{
struct merge_list *orig, *final;
const char *path;
- /* If it's already branch1, don't bother showing it */
- if (!branch1)
+ /* If it's already ours, don't bother showing it */
+ if (!ours)
return;
path = traverse_path(info, result);
- orig = create_entry(2, branch1->mode, branch1->sha1, path);
+ orig = create_entry(2, ours->mode, ours->sha1, path);
final = create_entry(0, result->mode, result->sha1, path);
final->link = orig;
@@ -192,34 +190,35 @@ static void resolve(const struct traverse_info *info, struct name_entry *branch1
add_merge_entry(final);
}
-static int unresolved_directory(const struct traverse_info *info, struct name_entry n[3])
+static void unresolved_directory(const struct traverse_info *info, struct name_entry n[3],
+ int df_conflict)
{
char *newbase;
struct name_entry *p;
struct tree_desc t[3];
void *buf0, *buf1, *buf2;
- if (!resolve_directories)
- return 0;
- p = n;
- if (!p->mode) {
- p++;
- if (!p->mode)
- p++;
+ for (p = n; p < n + 3; p++) {
+ if (p->mode && S_ISDIR(p->mode))
+ break;
}
- if (!S_ISDIR(p->mode))
- return 0;
+ if (n + 3 <= p)
+ return; /* there is no tree here */
+
newbase = traverse_path(info, p);
- buf0 = fill_tree_descriptor(t+0, n[0].sha1);
- buf1 = fill_tree_descriptor(t+1, n[1].sha1);
- buf2 = fill_tree_descriptor(t+2, n[2].sha1);
- merge_trees(t, newbase);
+
+#define ENTRY_SHA1(e) (((e)->mode && S_ISDIR((e)->mode)) ? (e)->sha1 : NULL)
+ buf0 = fill_tree_descriptor(t+0, ENTRY_SHA1(n + 0));
+ buf1 = fill_tree_descriptor(t+1, ENTRY_SHA1(n + 1));
+ buf2 = fill_tree_descriptor(t+2, ENTRY_SHA1(n + 2));
+#undef ENTRY_SHA1
+
+ merge_trees_recursive(t, newbase, df_conflict);
free(buf0);
free(buf1);
free(buf2);
free(newbase);
- return 1;
}
@@ -242,18 +241,26 @@ static struct merge_list *link_entry(unsigned stage, const struct traverse_info
static void unresolved(const struct traverse_info *info, struct name_entry n[3])
{
struct merge_list *entry = NULL;
+ int i;
+ unsigned dirmask = 0, mask = 0;
+
+ for (i = 0; i < 3; i++) {
+ mask |= (1 << i);
+ if (n[i].mode && S_ISDIR(n[i].mode))
+ dirmask |= (1 << i);
+ }
- if (unresolved_directory(info, n))
+ unresolved_directory(info, n, dirmask && (dirmask != mask));
+
+ if (dirmask == mask)
return;
- /*
- * Do them in reverse order so that the resulting link
- * list has the stages in order - link_entry adds new
- * links at the front.
- */
- entry = link_entry(3, info, n + 2, entry);
- entry = link_entry(2, info, n + 1, entry);
- entry = link_entry(1, info, n + 0, entry);
+ if (n[2].mode && !S_ISDIR(n[2].mode))
+ entry = link_entry(3, info, n + 2, entry);
+ if (n[1].mode && !S_ISDIR(n[1].mode))
+ entry = link_entry(2, info, n + 1, entry);
+ if (n[0].mode && !S_ISDIR(n[0].mode))
+ entry = link_entry(1, info, n + 0, entry);
add_merge_entry(entry);
}
@@ -292,20 +299,29 @@ static int threeway_callback(int n, unsigned long mask, unsigned long dirmask, s
/* Same in both? */
if (same_entry(entry+1, entry+2)) {
if (entry[0].sha1) {
+ /* Modified identically */
resolve(info, NULL, entry+1);
return mask;
}
+ /* "Both added the same" is left unresolved */
}
if (same_entry(entry+0, entry+1)) {
if (entry[2].sha1 && !S_ISDIR(entry[2].mode)) {
+ /* We did not touch, they modified -- take theirs */
resolve(info, entry+1, entry+2);
return mask;
}
+ /*
+ * If we did not touch a directory but they made it
+ * into a file, we fall through and unresolved()
+ * recurses down. Likewise for the opposite case.
+ */
}
if (same_entry(entry+0, entry+2)) {
if (entry[1].sha1 && !S_ISDIR(entry[1].mode)) {
+ /* We modified, they did not touch -- take ours */
resolve(info, NULL, entry+1);
return mask;
}
@@ -315,15 +331,21 @@ static int threeway_callback(int n, unsigned long mask, unsigned long dirmask, s
return mask;
}
-static void merge_trees(struct tree_desc t[3], const char *base)
+static void merge_trees_recursive(struct tree_desc t[3], const char *base, int df_conflict)
{
struct traverse_info info;
setup_traverse_info(&info, base);
+ info.data = &df_conflict;
info.fn = threeway_callback;
traverse_trees(3, t, &info);
}
+static void merge_trees(struct tree_desc t[3], const char *base)
+{
+ merge_trees_recursive(t, base, 0);
+}
+
static void *get_tree_descriptor(struct tree_desc *desc, const char *rev)
{
unsigned char sha1[20];
diff --git a/builtin/merge.c b/builtin/merge.c
index a96e8eac19..9307e9c726 100644
--- a/builtin/merge.c
+++ b/builtin/merge.c
@@ -800,8 +800,9 @@ static void prepare_to_commit(struct commit_list *remoteheads)
if (0 < option_edit)
strbuf_add_lines(&msg, "# ", comment, strlen(comment));
write_merge_msg(&msg);
- run_hook(get_index_file(), "prepare-commit-msg",
- git_path("MERGE_MSG"), "merge", NULL, NULL);
+ if (run_hook(get_index_file(), "prepare-commit-msg",
+ git_path("MERGE_MSG"), "merge", NULL, NULL))
+ abort_commit(remoteheads, NULL);
if (0 < option_edit) {
if (launch_editor(git_path("MERGE_MSG"), NULL, NULL))
abort_commit(remoteheads, NULL);
@@ -1221,6 +1222,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
memset(&opts, 0, sizeof(opts));
opts.add_title = !have_message;
opts.shortlog_len = shortlog_len;
+ opts.credit_people = (0 < option_edit);
fmt_merge_msg(&merge_names, &merge_msg, &opts);
if (merge_msg.len)
diff --git a/builtin/pack-redundant.c b/builtin/pack-redundant.c
index f5c6afc5dd..649c3aaa93 100644
--- a/builtin/pack-redundant.c
+++ b/builtin/pack-redundant.c
@@ -301,14 +301,14 @@ static void pll_free(struct pll *l)
*/
static struct pll * get_permutations(struct pack_list *list, int n)
{
- struct pll *subset, *ret = NULL, *new_pll = NULL, *pll;
+ struct pll *subset, *ret = NULL, *new_pll = NULL;
if (list == NULL || pack_list_size(list) < n || n == 0)
return NULL;
if (n == 1) {
while (list) {
- new_pll = xmalloc(sizeof(pll));
+ new_pll = xmalloc(sizeof(*new_pll));
new_pll->pl = NULL;
pack_list_insert(&new_pll->pl, list);
new_pll->next = ret;
@@ -321,7 +321,7 @@ static struct pll * get_permutations(struct pack_list *list, int n)
while (list->next) {
subset = get_permutations(list->next, n - 1);
while (subset) {
- new_pll = xmalloc(sizeof(pll));
+ new_pll = xmalloc(sizeof(*new_pll));
new_pll->pl = subset->pl;
pack_list_insert(&new_pll->pl, list);
new_pll->next = ret;
diff --git a/builtin/prune.c b/builtin/prune.c
index 8cb8b9186a..85843d4f17 100644
--- a/builtin/prune.c
+++ b/builtin/prune.c
@@ -149,9 +149,7 @@ int cmd_prune(int argc, const char **argv, const char *prefix)
const char *name = *argv++;
if (!get_sha1(name, sha1)) {
- struct object *object = parse_object(sha1);
- if (!object)
- die("bad object: %s", name);
+ struct object *object = parse_object_or_die(sha1, name);
add_pending_object(&revs, object, "");
}
else
diff --git a/builtin/shortlog.c b/builtin/shortlog.c
index b316cf37ca..83605143ac 100644
--- a/builtin/shortlog.c
+++ b/builtin/shortlog.c
@@ -306,9 +306,8 @@ parse_done:
static void add_wrapped_shortlog_msg(struct strbuf *sb, const char *s,
const struct shortlog *log)
{
- int col = strbuf_add_wrapped_text(sb, s, log->in1, log->in2, log->wrap);
- if (col != log->wrap)
- strbuf_addch(sb, '\n');
+ strbuf_add_wrapped_text(sb, s, log->in1, log->in2, log->wrap);
+ strbuf_addch(sb, '\n');
}
void shortlog_output(struct shortlog *log)
diff --git a/builtin/update-index.c b/builtin/update-index.c
index ada1dff846..5c7762eef4 100644
--- a/builtin/update-index.c
+++ b/builtin/update-index.c
@@ -796,7 +796,7 @@ int cmd_update_index(int argc, const char **argv, const char *prefix)
};
if (argc == 2 && !strcmp(argv[1], "-h"))
- usage(update_index_usage[0]);
+ usage_with_options(update_index_usage, options);
git_config(git_default_config, NULL);