diff --git a/Documentation/git-init.txt b/Documentation/git-init.txt new file mode 100644 index 0000000000..36838c753b --- /dev/null +++ b/Documentation/git-init.txt @@ -0,0 +1 @@ +include::git-init-db.txt[] diff --git a/Makefile b/Makefile index de746befe5..963a8f64e9 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,5 @@ # The default target of this Makefile is... -all: +all:: # Define NO_OPENSSL environment variable if you do not have OpenSSL. # This also implies MOZILLA_SHA1. @@ -203,7 +203,7 @@ PROGRAMS = \ git-update-server-info$X \ git-upload-pack$X git-verify-pack$X \ git-pack-redundant$X git-var$X \ - git-describe$X git-merge-tree$X git-imap-send$X \ + git-merge-tree$X git-imap-send$X \ git-merge-recursive$X \ $(EXTRA_PROGRAMS) @@ -274,6 +274,7 @@ BUILTIN_OBJS = \ builtin-check-ref-format.o \ builtin-commit-tree.o \ builtin-count-objects.o \ + builtin-describe.o \ builtin-diff.o \ builtin-diff-files.o \ builtin-diff-index.o \ @@ -604,9 +605,12 @@ export prefix TAR INSTALL DESTDIR SHELL_PATH template_dir ### Build rules -all: $(ALL_PROGRAMS) $(BUILT_INS) git$X gitk gitweb/gitweb.cgi +all:: $(ALL_PROGRAMS) $(BUILT_INS) git$X gitk gitweb/gitweb.cgi +ifneq (,$X) + $(foreach p,$(patsubst %$X,%,$(filter %$X,$(ALL_PROGRAMS) $(BUILT_INS) git$X)), rm -f '$p';) +endif -all: +all:: $(MAKE) -C perl PERL_PATH='$(PERL_PATH_SQ)' prefix='$(prefix_SQ)' all $(MAKE) -C templates @@ -848,6 +852,9 @@ install: all '$(DESTDIR_SQ)$(gitexecdir_SQ)/git$X'; \ fi $(foreach p,$(BUILT_INS), rm -f '$(DESTDIR_SQ)$(gitexecdir_SQ)/$p' && ln '$(DESTDIR_SQ)$(gitexecdir_SQ)/git$X' '$(DESTDIR_SQ)$(gitexecdir_SQ)/$p' ;) +ifneq (,$X) + $(foreach p,$(patsubst %$X,%,$(filter %$X,$(ALL_PROGRAMS) $(BUILT_INS) git$X)), rm -f '$(DESTDIR_SQ)$(gitexecdir_SQ)/$p';) +endif install-doc: $(MAKE) -C Documentation install diff --git a/describe.c b/builtin-describe.c similarity index 97% rename from describe.c rename to builtin-describe.c index f4029ee74e..ad3b469f37 100644 --- a/describe.c +++ b/builtin-describe.c @@ -2,6 +2,7 @@ #include "commit.h" #include "tag.h" #include "refs.h" +#include "builtin.h" #define SEEN (1u << 0) @@ -139,7 +140,7 @@ static void describe(const char *arg, int last_one) die("cannot describe '%s'", sha1_to_hex(cmit->object.sha1)); } -int main(int argc, char **argv) +int cmd_describe(int argc, const char **argv, const char *prefix) { int i; @@ -161,7 +162,7 @@ int main(int argc, char **argv) usage(describe_usage); } - setup_git_directory(); + save_commit_buffer = 0; if (argc <= i) describe("HEAD", 1); diff --git a/builtin.h b/builtin.h index ae32993ce9..818c7bf04d 100644 --- a/builtin.h +++ b/builtin.h @@ -25,6 +25,7 @@ extern int cmd_check_ref_format(int argc, const char **argv, const char *prefix) extern int cmd_cherry(int argc, const char **argv, const char *prefix); extern int cmd_commit_tree(int argc, const char **argv, const char *prefix); extern int cmd_count_objects(int argc, const char **argv, const char *prefix); +extern int cmd_describe(int argc, const char **argv, const char *prefix); extern int cmd_diff_files(int argc, const char **argv, const char *prefix); extern int cmd_diff_index(int argc, const char **argv, const char *prefix); extern int cmd_diff(int argc, const char **argv, const char *prefix); diff --git a/git-send-email.perl b/git-send-email.perl index ba39d39384..8dc2ee0cf7 100755 --- a/git-send-email.perl +++ b/git-send-email.perl @@ -402,6 +402,15 @@ sub make_message_id $cc = ""; $time = time - scalar $#files; +sub unquote_rfc2047 { + local ($_) = @_; + if (s/=\?utf-8\?q\?(.*)\?=/$1/g) { + s/_/ /g; + s/=([0-9A-F]{2})/chr(hex($1))/eg; + } + return "$_ - unquoted"; +} + sub send_message { my @recipients = unique_email_list(@to); @@ -555,6 +564,7 @@ foreach my $t (@files) { } close F; if (defined $author_not_sender) { + $author_not_sender = unquote_rfc2047($author_not_sender); $message = "From: $author_not_sender\n\n$message"; } diff --git a/git.c b/git.c index e7bc79af93..9a0185cc43 100644 --- a/git.c +++ b/git.c @@ -220,6 +220,7 @@ static void handle_internal_command(int argc, const char **argv, char **envp) { "cherry", cmd_cherry, RUN_SETUP }, { "commit-tree", cmd_commit_tree, RUN_SETUP }, { "count-objects", cmd_count_objects, RUN_SETUP }, + { "describe", cmd_describe, RUN_SETUP }, { "diff", cmd_diff, RUN_SETUP | USE_PAGER }, { "diff-files", cmd_diff_files, RUN_SETUP }, { "diff-index", cmd_diff_index, RUN_SETUP }, diff --git a/merge-recursive.c b/merge-recursive.c index 87a27e0379..5237021309 100644 --- a/merge-recursive.c +++ b/merge-recursive.c @@ -110,35 +110,6 @@ static void output_commit_title(struct commit *commit) } } -static const char *current_index_file = NULL; -static const char *original_index_file; -static const char *temporary_index_file; -static int cache_dirty = 0; - -static int flush_cache(void) -{ - /* flush temporary index */ - struct lock_file *lock = xcalloc(1, sizeof(struct lock_file)); - int fd = hold_lock_file_for_update(lock, current_index_file, 1); - if (write_cache(fd, active_cache, active_nr) || - close(fd) || commit_lock_file(lock)) - die ("unable to write %s", current_index_file); - discard_cache(); - cache_dirty = 0; - return 0; -} - -static void setup_index(int temp) -{ - current_index_file = temp ? temporary_index_file: original_index_file; - if (cache_dirty) { - discard_cache(); - cache_dirty = 0; - } - unlink(temporary_index_file); - discard_cache(); -} - static struct cache_entry *make_cache_entry(unsigned int mode, const unsigned char *sha1, const char *path, int stage, int refresh) { @@ -167,9 +138,6 @@ static int add_cacheinfo(unsigned int mode, const unsigned char *sha1, const char *path, int stage, int refresh, int options) { struct cache_entry *ce; - if (!cache_dirty) - read_cache_from(current_index_file); - cache_dirty++; ce = make_cache_entry(mode, sha1 ? sha1 : null_sha1, path, stage, refresh); if (!ce) return error("cache_addinfo failed: %s", strerror(cache_errno)); @@ -187,26 +155,6 @@ static int add_cacheinfo(unsigned int mode, const unsigned char *sha1, */ static int index_only = 0; -static int git_read_tree(struct tree *tree) -{ - int rc; - struct object_list *trees = NULL; - struct unpack_trees_options opts; - - if (cache_dirty) - die("read-tree with dirty cache"); - - memset(&opts, 0, sizeof(opts)); - object_list_append(&tree->object, &trees); - rc = unpack_trees(trees, &opts); - cache_tree_free(&active_cache_tree); - - if (rc == 0) - cache_dirty = 1; - - return rc; -} - static int git_merge_trees(int index_only, struct tree *common, struct tree *head, @@ -216,11 +164,6 @@ static int git_merge_trees(int index_only, struct object_list *trees = NULL; struct unpack_trees_options opts; - if (!cache_dirty) { - read_cache_from(current_index_file); - cache_dirty = 1; - } - memset(&opts, 0, sizeof(opts)); if (index_only) opts.index_only = 1; @@ -236,39 +179,37 @@ static int git_merge_trees(int index_only, rc = unpack_trees(trees, &opts); cache_tree_free(&active_cache_tree); - - cache_dirty = 1; - return rc; } +static int unmerged_index(void) +{ + int i; + for (i = 0; i < active_nr; i++) { + struct cache_entry *ce = active_cache[i]; + if (ce_stage(ce)) + return 1; + } + return 0; +} + static struct tree *git_write_tree(void) { struct tree *result = NULL; - if (cache_dirty) { - unsigned i; - for (i = 0; i < active_nr; i++) { - struct cache_entry *ce = active_cache[i]; - if (ce_stage(ce)) - return NULL; - } - } else - read_cache_from(current_index_file); + if (unmerged_index()) + return NULL; if (!active_cache_tree) active_cache_tree = cache_tree(); if (!cache_tree_fully_valid(active_cache_tree) && - cache_tree_update(active_cache_tree, - active_cache, active_nr, 0, 0) < 0) + cache_tree_update(active_cache_tree, + active_cache, active_nr, 0, 0) < 0) die("error building trees"); result = lookup_tree(active_cache_tree->sha1); - flush_cache(); - cache_dirty = 0; - return result; } @@ -331,10 +272,7 @@ static struct path_list *get_unmerged(void) int i; unmerged->strdup_paths = 1; - if (!cache_dirty) { - read_cache_from(current_index_file); - cache_dirty++; - } + for (i = 0; i < active_nr; i++) { struct path_list_item *item; struct stage_data *e; @@ -469,9 +407,6 @@ static int remove_file(int clean, const char *path, int no_wd) int update_working_directory = !index_only && !no_wd; if (update_cache) { - if (!cache_dirty) - read_cache_from(current_index_file); - cache_dirty++; if (remove_file_from_cache(path)) return -1; } @@ -954,8 +889,6 @@ static int process_renames(struct path_list *a_renames, path_list_clear(&a_by_dst, 0); path_list_clear(&b_by_dst, 0); - if (cache_dirty) - flush_cache(); return clean_merge; } @@ -1083,9 +1016,6 @@ static int process_entry(const char *path, struct stage_data *entry, } else die("Fatal merge failure, shouldn't happen."); - if (cache_dirty) - flush_cache(); - return clean_merge; } @@ -1110,9 +1040,7 @@ static int merge_trees(struct tree *head, sha1_to_hex(head->object.sha1), sha1_to_hex(merge->object.sha1)); - *result = git_write_tree(); - - if (!*result) { + if (unmerged_index()) { struct path_list *entries, *re_head, *re_merge; int i; path_list_clear(¤t_file_set, 1); @@ -1138,10 +1066,6 @@ static int merge_trees(struct tree *head, path_list_clear(re_head, 0); path_list_clear(entries, 1); - if (clean || index_only) - *result = git_write_tree(); - else - *result = NULL; } else { clean = 1; printf("merging of trees %s and %s resulted in %s\n", @@ -1149,6 +1073,8 @@ static int merge_trees(struct tree *head, sha1_to_hex(merge->object.sha1), sha1_to_hex((*result)->object.sha1)); } + if (index_only) + *result = git_write_tree(); return clean; } @@ -1173,10 +1099,10 @@ static int merge(struct commit *h1, const char *branch1, const char *branch2, int call_depth /* =0 */, - struct commit *ancestor /* =None */, + struct commit_list *ca, struct commit **result) { - struct commit_list *ca = NULL, *iter; + struct commit_list *iter; struct commit *merged_common_ancestors; struct tree *mrtree; int clean; @@ -1185,10 +1111,10 @@ static int merge(struct commit *h1, output_commit_title(h1); output_commit_title(h2); - if (ancestor) - commit_list_insert(ancestor, &ca); - else - ca = reverse_commit_list(get_merge_bases(h1, h2, 1)); + if (!ca) { + ca = get_merge_bases(h1, h2, 1); + ca = reverse_commit_list(ca); + } output("found %u common ancestor(s):", commit_list_count(ca)); for (iter = ca; iter; iter = iter->next) @@ -1214,6 +1140,7 @@ static int merge(struct commit *h1, * merge_trees has always overwritten it: the commited * "conflicts" were already resolved. */ + discard_cache(); merge(merged_common_ancestors, iter->item, "Temporary merge branch 1", "Temporary merge branch 2", @@ -1226,25 +1153,21 @@ static int merge(struct commit *h1, die("merge returned no commit"); } + discard_cache(); if (call_depth == 0) { - setup_index(0 /* $GIT_DIR/index */); + read_cache(); index_only = 0; - } else { - setup_index(1 /* temporary index */); - git_read_tree(h1->tree); + } else index_only = 1; - } clean = merge_trees(h1->tree, h2->tree, merged_common_ancestors->tree, branch1, branch2, &mrtree); - if (!ancestor && (clean || index_only)) { + if (index_only) { *result = make_virtual_commit(mrtree, "merged tree"); commit_list_insert(h1, &(*result)->parents); commit_list_insert(h2, &(*result)->parents->next); - } else - *result = NULL; - + } return clean; } @@ -1280,19 +1203,16 @@ static struct commit *get_ref(const char *ref) int main(int argc, char *argv[]) { - static const char *bases[2]; + static const char *bases[20]; static unsigned bases_count = 0; int i, clean; const char *branch1, *branch2; struct commit *result, *h1, *h2; + struct commit_list *ca = NULL; + struct lock_file *lock = xcalloc(1, sizeof(struct lock_file)); + int index_fd; git_config(git_default_config); /* core.filemode */ - original_index_file = getenv(INDEX_ENVIRONMENT); - - if (!original_index_file) - original_index_file = xstrdup(git_path("index")); - - temporary_index_file = xstrdup(git_path("mrg-rcrsv-tmp-idx")); if (argc < 4) die("Usage: %s ... -- ...\n", argv[0]); @@ -1316,18 +1236,18 @@ int main(int argc, char *argv[]) branch2 = better_branch_name(branch2); printf("Merging %s with %s\n", branch1, branch2); - if (bases_count == 1) { - struct commit *ancestor = get_ref(bases[0]); - clean = merge(h1, h2, branch1, branch2, 0, ancestor, &result); - } else - clean = merge(h1, h2, branch1, branch2, 0, NULL, &result); + index_fd = hold_lock_file_for_update(lock, get_index_file(), 1); - if (cache_dirty) - flush_cache(); + for (i = 0; i < bases_count; i++) { + struct commit *ancestor = get_ref(bases[i]); + ca = commit_list_insert(ancestor, &ca); + } + clean = merge(h1, h2, branch1, branch2, 0, ca, &result); + + if (active_cache_changed && + (write_cache(index_fd, active_cache, active_nr) || + close(index_fd) || commit_lock_file(lock))) + die ("unable to write %s", get_index_file()); return clean ? 0: 1; } - -/* -vim: sw=8 noet -*/ diff --git a/t/t1410-reflog.sh b/t/t1410-reflog.sh index 738d1513d4..8e8d526ef2 100755 --- a/t/t1410-reflog.sh +++ b/t/t1410-reflog.sh @@ -71,6 +71,8 @@ test_expect_success setup ' check_fsck && chmod +x C && + ( test "`git repo-config --bool core.filemode`" != false || + echo executable >>C ) && git add C && test_tick && git commit -m dragon && L=`git rev-parse --verify HEAD` && diff --git a/wt-status.c b/wt-status.c index 2a002baabd..9e4b9e1172 100644 --- a/wt-status.c +++ b/wt-status.c @@ -47,10 +47,11 @@ void wt_status_prepare(struct wt_status *s) s->reference = "HEAD"; s->amend = 0; s->verbose = 0; - s->commitable = 0; s->untracked = 0; - s->workdir_clean = 1; + s->commitable = 0; + s->workdir_dirty = 0; + s->workdir_untracked = 0; } static void wt_status_print_cached_header(const char *reference) @@ -176,7 +177,7 @@ static void wt_status_print_changed_cb(struct diff_queue_struct *q, struct wt_status *s = data; int i; if (q->nr) { - s->workdir_clean = 0; + s->workdir_dirty = 1; wt_status_print_header("Changed but not added", use_add_msg); } for (i = 0; i < q->nr; i++) @@ -263,7 +264,7 @@ static void wt_status_print_untracked(struct wt_status *s) continue; } if (!shown_header) { - s->workdir_clean = 0; + s->workdir_untracked = 1; wt_status_print_header("Untracked files", use_add_msg); shown_header = 1; } @@ -320,12 +321,14 @@ void wt_status_print(struct wt_status *s) if (!s->commitable) { if (s->amend) printf("# No changes\n"); - else if (s->workdir_clean) - printf(s->is_initial - ? "nothing to commit\n" - : "nothing to commit (working directory matches HEAD)\n"); - else + else if (s->workdir_dirty) printf("no changes added to commit (use \"git add\" and/or \"git commit [-a|-i|-o]\")\n"); + else if (s->workdir_untracked) + printf("nothing added to commit but untracked files present (use \"git add\" to track)\n"); + else if (s->is_initial) + printf("nothing to commit (create/copy files and use \"git add\" to track)\n"); + else + printf("nothing to commit (working directory clean)\n"); } } diff --git a/wt-status.h b/wt-status.h index 892a86c76a..cfea4ae688 100644 --- a/wt-status.h +++ b/wt-status.h @@ -12,11 +12,13 @@ struct wt_status { int is_initial; char *branch; const char *reference; - int commitable; int verbose; int amend; int untracked; - int workdir_clean; + /* These are computed during processing of the individual sections */ + int commitable; + int workdir_dirty; + int workdir_untracked; }; int git_status_config(const char *var, const char *value);