Merge branch 'jv/merge-nothing-into-void'
authorJunio C Hamano <gitster@pobox.com>
Wed, 6 Apr 2016 18:39:11 +0000 (11:39 -0700)
committerJunio C Hamano <gitster@pobox.com>
Wed, 6 Apr 2016 18:39:11 +0000 (11:39 -0700)
"git merge FETCH_HEAD" dereferenced NULL pointer when merging
nothing into an unborn history (which is arguably unusual usage,
which perhaps was the reason why nobody noticed it).

* jv/merge-nothing-into-void:
merge: fix NULL pointer dereference when merging nothing into void

1  2 
builtin/merge.c
t/t7600-merge.sh
diff --combined builtin/merge.c
index c8154aaf6a5afa87ab42d3db632798698a9f2b1d,bf2f2614fbb5ba82df3dca5cad8f79dbe605feff..30b7bd54fab38beed4ef1b48a4aacda0fb018987
@@@ -1187,7 -1187,6 +1187,7 @@@ int cmd_merge(int argc, const char **ar
        else
                head_commit = lookup_commit_or_die(head_sha1, "HEAD");
  
 +      init_diff_ui_defaults();
        git_config(git_merge_config, NULL);
  
        if (branch_mergeoptions)
                        builtin_merge_options);
  
        if (!head_commit) {
-               struct commit *remote_head;
                /*
                 * If the merged head is a valid one there is no reason
                 * to forbid "git merge" into a branch yet to be born.
                 * We do the same for "git pull".
                 */
+               unsigned char *remote_head_sha1;
                if (squash)
                        die(_("Squash commit into empty head not supported yet"));
                if (fast_forward == FF_NO)
                            "an empty head"));
                remoteheads = collect_parents(head_commit, &head_subsumed,
                                              argc, argv, NULL);
-               remote_head = remoteheads->item;
-               if (!remote_head)
+               if (!remoteheads)
                        die(_("%s - not something we can merge"), argv[0]);
                if (remoteheads->next)
                        die(_("Can merge only exactly one commit into empty head"));
-               read_empty(remote_head->object.oid.hash, 0);
-               update_ref("initial pull", "HEAD", remote_head->object.oid.hash,
+               remote_head_sha1 = remoteheads->item->object.oid.hash;
+               read_empty(remote_head_sha1, 0);
+               update_ref("initial pull", "HEAD", remote_head_sha1,
                           NULL, 0, UPDATE_REFS_DIE_ON_ERR);
                goto done;
        }
diff --combined t/t7600-merge.sh
index dc9f142f537e53de34156a9c7fddf3be49a0e219,9d7952f42c0d21180592d4d31d7547141038a22d..85248a14b61d68b61932d595eb0fa8fcaa8506b1
@@@ -33,11 -33,9 +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 () {
@@@ -130,12 -128,6 +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 &&
@@@ -226,26 -218,6 +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' '
@@@ -753,4 -725,14 +753,14 @@@ test_expect_success 'merge detects mod-
        test_must_fail git merge -s resolve master
  '
  
+ test_expect_success 'merge nothing into void' '
+       git init void &&
+       (
+               cd void &&
+               git remote add up .. &&
+               git fetch up &&
+               test_must_fail git merge FETCH_HEAD
+       )
+ '
  test_done