Merge branch 'ss/commit-squash-msg' into maint
authorJunio C Hamano <gitster@pobox.com>
Fri, 15 Apr 2016 01:57:48 +0000 (18:57 -0700)
committerJunio C Hamano <gitster@pobox.com>
Fri, 15 Apr 2016 01:57:48 +0000 (18:57 -0700)
When "git merge --squash" stopped due to conflict, the concluding
"git commit" failed to read in the SQUASH_MSG that shows the log
messages from all the squashed commits.

* ss/commit-squash-msg:
commit: do not lose SQUASH_MSG contents

1  2 
builtin/commit.c
t/t7600-merge.sh
diff --combined builtin/commit.c
index b3bd2d41813f80d848afc199c2fae92cae6b6c11,6163972b8a6edd5a0e0b6a3911e414112a64e55b..c733ec98b7057b6310db6b364d5780170455dbaa
@@@ -32,7 -32,6 +32,7 @@@
  #include "sequencer.h"
  #include "notes-utils.h"
  #include "mailmap.h"
 +#include "sigchain.h"
  
  static const char * const builtin_commit_usage[] = {
        N_("git commit [<options>] [--] <pathspec>..."),
@@@ -300,7 -299,7 +300,7 @@@ static void create_base_index(const str
        opts.dst_index = &the_index;
  
        opts.fn = oneway_merge;
 -      tree = parse_tree_indirect(current_head->object.sha1);
 +      tree = parse_tree_indirect(current_head->object.oid.hash);
        if (!tree)
                die(_("failed to unpack HEAD tree object"));
        parse_tree(tree);
@@@ -325,7 -324,6 +325,7 @@@ static const char *prepare_index(int ar
        struct string_list partial;
        struct pathspec pathspec;
        int refresh_flags = REFRESH_QUIET;
 +      const char *ret;
  
        if (is_status)
                refresh_flags |= REFRESH_UNMERGED;
                        die(_("unable to create temporary index"));
  
                old_index_env = getenv(INDEX_ENVIRONMENT);
 -              setenv(INDEX_ENVIRONMENT, index_lock.filename.buf, 1);
 +              setenv(INDEX_ENVIRONMENT, get_lock_file_path(&index_lock), 1);
  
                if (interactive_add(argc, argv, prefix, patch_interactive) != 0)
                        die(_("interactive add failed"));
                        unsetenv(INDEX_ENVIRONMENT);
  
                discard_cache();
 -              read_cache_from(index_lock.filename.buf);
 +              read_cache_from(get_lock_file_path(&index_lock));
                if (update_main_cache_tree(WRITE_TREE_SILENT) == 0) {
                        if (reopen_lock_file(&index_lock) < 0)
                                die(_("unable to write index file"));
                        warning(_("Failed to update main cache tree"));
  
                commit_style = COMMIT_NORMAL;
 -              return index_lock.filename.buf;
 +              return get_lock_file_path(&index_lock);
        }
  
        /*
                if (write_locked_index(&the_index, &index_lock, CLOSE_LOCK))
                        die(_("unable to write new_index file"));
                commit_style = COMMIT_NORMAL;
 -              return index_lock.filename.buf;
 +              return get_lock_file_path(&index_lock);
        }
  
        /*
                hold_locked_index(&index_lock, 1);
                refresh_cache_or_die(refresh_flags);
                if (active_cache_changed
 -                  || !cache_tree_fully_valid(active_cache_tree)) {
 +                  || !cache_tree_fully_valid(active_cache_tree))
                        update_main_cache_tree(WRITE_TREE_SILENT);
 -                      active_cache_changed = 1;
 -              }
                if (active_cache_changed) {
                        if (write_locked_index(&the_index, &index_lock,
                                               COMMIT_LOCK))
                die(_("unable to write temporary index file"));
  
        discard_cache();
 -      read_cache_from(false_lock.filename.buf);
 -
 -      return false_lock.filename.buf;
 +      ret = get_lock_file_path(&false_lock);
 +      read_cache_from(ret);
 +      return ret;
  }
  
  static int run_status(FILE *fp, const char *index_file, const char *prefix, int nowarn,
@@@ -726,9 -726,18 +726,18 @@@ static int prepare_to_commit(const cha
                                      &sb, &ctx);
                hook_arg1 = "message";
        } else if (!stat(git_path_merge_msg(), &statbuf)) {
+               /*
+                * prepend SQUASH_MSG here if it exists and a
+                * "merge --squash" was originally performed
+                */
+               if (!stat(git_path_squash_msg(), &statbuf)) {
+                       if (strbuf_read_file(&sb, git_path_squash_msg(), 0) < 0)
+                               die_errno(_("could not read SQUASH_MSG"));
+                       hook_arg1 = "squash";
+               } else
+                       hook_arg1 = "merge";
                if (strbuf_read_file(&sb, git_path_merge_msg(), 0) < 0)
                        die_errno(_("could not read MERGE_MSG"));
-               hook_arg1 = "merge";
        } else if (!stat(git_path_squash_msg(), &statbuf)) {
                if (strbuf_read_file(&sb, git_path_squash_msg(), 0) < 0)
                        die_errno(_("could not read SQUASH_MSG"));
                hook_arg2 = "";
        }
  
 -      s->fp = fopen(git_path(commit_editmsg), "w");
 +      s->fp = fopen_for_writing(git_path(commit_editmsg));
        if (s->fp == NULL)
                die_errno(_("could not open '%s'"), git_path(commit_editmsg));
  
        s->hints = 0;
  
        if (clean_message_contents)
 -              stripspace(&sb, 0);
 +              strbuf_stripspace(&sb, 0);
  
        if (signoff)
                append_signoff(&sb, ignore_non_trailer(&sb), 0);
@@@ -1015,7 -1024,7 +1024,7 @@@ static int template_untouched(struct st
        if (!template_file || strbuf_read_file(&tmpl, template_file, 0) <= 0)
                return 0;
  
 -      stripspace(&tmpl, cleanup_mode == CLEANUP_ALL);
 +      strbuf_stripspace(&tmpl, cleanup_mode == CLEANUP_ALL);
        if (!skip_prefix(sb->buf, tmpl.buf, &start))
                start = sb->buf;
        strbuf_release(&tmpl);
@@@ -1538,10 -1547,8 +1547,10 @@@ static int run_rewrite_hook(const unsig
                return code;
        n = snprintf(buf, sizeof(buf), "%s %s\n",
                     sha1_to_hex(oldsha1), sha1_to_hex(newsha1));
 +      sigchain_push(SIGPIPE, SIG_IGN);
        write_in_full(proc.in, buf, n);
        close(proc.in);
 +      sigchain_pop(SIGPIPE);
        return finish_command(&proc);
  }
  
@@@ -1690,7 -1697,7 +1699,7 @@@ int cmd_commit(int argc, const char **a
                if (fp == NULL)
                        die_errno(_("could not open '%s' for reading"),
                                  git_path_merge_head());
 -              while (strbuf_getline(&m, fp, '\n') != EOF) {
 +              while (strbuf_getline_lf(&m, fp) != EOF) {
                        struct commit *parent;
  
                        parent = get_merge_parent(m.buf);
                wt_status_truncate_message_at_cut_line(&sb);
  
        if (cleanup_mode != CLEANUP_NONE)
 -              stripspace(&sb, cleanup_mode == CLEANUP_ALL);
 +              strbuf_stripspace(&sb, cleanup_mode == CLEANUP_ALL);
        if (template_untouched(&sb) && !allow_empty_message) {
                rollback_index_files();
                fprintf(stderr, _("Aborting commit; you did not edit the message.\n"));
        if (!transaction ||
            ref_transaction_update(transaction, "HEAD", sha1,
                                   current_head
 -                                 ? current_head->object.sha1 : null_sha1,
 +                                 ? current_head->object.oid.hash : null_sha1,
                                   0, sb.buf, &err) ||
            ref_transaction_commit(transaction, &err)) {
                rollback_index_files();
                cfg = init_copy_notes_for_rewrite("amend");
                if (cfg) {
                        /* we are amending, so current_head is not NULL */
 -                      copy_note_for_rewrite(cfg, current_head->object.sha1, sha1);
 +                      copy_note_for_rewrite(cfg, current_head->object.oid.hash, sha1);
                        finish_copy_notes_for_rewrite(cfg, "Notes added by 'git commit --amend'");
                }
 -              run_rewrite_hook(current_head->object.sha1, sha1);
 +              run_rewrite_hook(current_head->object.oid.hash, sha1);
        }
        if (!quiet)
                print_summary(prefix, sha1, !current_head);
diff --combined t/t7600-merge.sh
index 302e23826341bce6c3797330b5f2996877dc5baf,55b9da45728ace3e3824205abbc7d9fb5f542fe9..dc9f142f537e53de34156a9c7fddf3be49a0e219
@@@ -33,9 -33,11 +33,11 @@@ printf '%s\n' 1 2 3 4 5 6 7 8 9 >fil
  printf '%s\n' '1 X' 2 3 4 5 6 7 8 9 >file.1
  printf '%s\n' 1 2 3 4 '5 X' 6 7 8 9 >file.5
  printf '%s\n' 1 2 3 4 5 6 7 8 '9 X' >file.9
+ printf '%s\n' 1 2 3 4 5 6 7 8 '9 Y' >file.9y
  printf '%s\n' '1 X' 2 3 4 5 6 7 8 9 >result.1
  printf '%s\n' '1 X' 2 3 4 '5 X' 6 7 8 9 >result.1-5
  printf '%s\n' '1 X' 2 3 4 '5 X' 6 7 8 '9 X' >result.1-5-9
+ printf '%s\n' 1 2 3 4 5 6 7 8 '9 Z' >result.9z
  >empty
  
  create_merge_msgs () {
@@@ -128,6 -130,12 +130,12 @@@ test_expect_success 'setup' 
        git tag c2 &&
        c2=$(git rev-parse HEAD) &&
        git reset --hard "$c0" &&
+       cp file.9y file &&
+       git add file &&
+       test_tick &&
+       git commit -m "commit 7" &&
+       git tag c7 &&
+       git reset --hard "$c0" &&
        cp file.9 file &&
        git add file &&
        test_tick &&
@@@ -218,6 -226,26 +226,26 @@@ test_expect_success 'merge c1 with c2' 
        verify_parents $c1 $c2
  '
  
+ test_expect_success 'merge --squash c3 with c7' '
+       git reset --hard c3 &&
+       test_must_fail git merge --squash c7 &&
+       cat result.9z >file &&
+       git commit --no-edit -a &&
+       {
+               cat <<-EOF
+               Squashed commit of the following:
+               $(git show -s c7)
+               # Conflicts:
+               #       file
+               EOF
+       } >expect &&
+       git cat-file commit HEAD | sed -e '1,/^$/d' >actual &&
+       test_cmp expect actual
+ '
  test_debug 'git log --graph --decorate --oneline --all'
  
  test_expect_success 'merge c1 with c2 and c3' '
@@@ -692,37 -720,4 +720,37 @@@ test_expect_success GPG 'merge --no-edi
        test_cmp actual expect
  '
  
 +test_expect_success 'set up mod-256 conflict scenario' '
 +      # 256 near-identical stanzas...
 +      for i in $(test_seq 1 256); do
 +              for j in 1 2 3 4 5; do
 +                      echo $i-$j
 +              done
 +      done >file &&
 +      git add file &&
 +      git commit -m base &&
 +
 +      # one side changes the first line of each to "master"
 +      sed s/-1/-master/ <file >tmp &&
 +      mv tmp file &&
 +      git commit -am master &&
 +
 +      # and the other to "side"; merging the two will
 +      # yield 256 separate conflicts
 +      git checkout -b side HEAD^ &&
 +      sed s/-1/-side/ <file >tmp &&
 +      mv tmp file &&
 +      git commit -am side
 +'
 +
 +test_expect_success 'merge detects mod-256 conflicts (recursive)' '
 +      git reset --hard &&
 +      test_must_fail git merge -s recursive master
 +'
 +
 +test_expect_success 'merge detects mod-256 conflicts (resolve)' '
 +      git reset --hard &&
 +      test_must_fail git merge -s resolve master
 +'
 +
  test_done