git-merge: make it usable as the first class UI
authorJunio C Hamano <junkio@cox.net>
Mon, 20 Nov 2006 09:06:09 +0000 (01:06 -0800)
committerJunio C Hamano <junkio@cox.net>
Wed, 22 Nov 2006 04:55:40 +0000 (20:55 -0800)
This teaches the oft-requested syntax

git merge $commit

to implement merging the named commit to the current branch.
This hopefully would make "git merge" usable as the first class
UI instead of being a mere backend for "git pull".

Most notably, $commit above can be any committish, so you can
say for example:

git merge js/shortlog~2

to merge early part of a topic branch without merging the rest
of it.

A custom merge message can be given with the new --message=<msg>
parameter.  The message is prepended in front of the usual
"Merge ..." message autogenerated with fmt-merge-message.

Signed-off-by: Junio C Hamano <junkio@cox.net>
Documentation/git-merge.txt
git-merge.sh

index bebf30ad3db951c0a0bad01ebee619821781eb39..e2954aa76eef46101f38683eb346bd31bf711a40 100644 (file)
@@ -8,12 +8,14 @@ git-merge - Grand Unified Merge Driver
 
 SYNOPSIS
 --------
-'git-merge' [-n] [--no-commit] [-s <strategy>]... <msg> <head> <remote> <remote>...
-
+[verse]
+'git-merge' [-n] [--no-commit] [--squash] [-s <strategy>]...
+       [--reflog-action=<action>]
+       -m=<msg> <remote> <remote>...
 
 DESCRIPTION
 -----------
-This is the top-level user interface to the merge machinery
+This is the top-level interface to the merge machinery
 which drives multiple merge strategy scripts.
 
 
@@ -27,13 +29,19 @@ include::merge-options.txt[]
        to give a good default for automated `git-merge` invocations.
 
 <head>::
-       our branch head commit.
+       Our branch head commit.  This has to be `HEAD`, so new
+       syntax does not require it
 
 <remote>::
-       other branch head merged into our branch.  You need at
+       Other branch head merged into our branch.  You need at
        least one <remote>.  Specifying more than one <remote>
        obviously means you are trying an Octopus.
 
+--reflog-action=<action>::
+       This is used internally when `git-pull` calls this command
+       to record that the merge was created by `pull` command
+       in the `ref-log` entry that results from the merge.
+
 include::merge-strategies.txt[]
 
 
index 84c3acfe63081b1c10ec171fa10246e0330efac8..25deb1e867ec01c65d223733a22edd98f18e241c 100755 (executable)
@@ -3,7 +3,8 @@
 # Copyright (c) 2005 Junio C Hamano
 #
 
-USAGE='[-n] [--no-commit] [--squash] [-s <strategy>]... <merge-message> <head> <remote>+'
+USAGE='[-n] [--no-commit] [--squash] [-s <strategy>] [--reflog-action=<action>] [-m=<merge-message>] <commit>+'
+
 . git-sh-setup
 
 LF='
@@ -92,7 +93,7 @@ finish () {
 
 case "$#" in 0) usage ;; esac
 
-rloga=
+rloga= have_message=
 while case "$#" in 0) break ;; esac
 do
        case "$1" in
@@ -125,17 +126,63 @@ do
        --reflog-action=*)
                rloga=`expr "z$1" : 'z-[^=]*=\(.*\)'`
                ;;
+       -m=*|--m=*|--me=*|--mes=*|--mess=*|--messa=*|--messag=*|--message=*)
+               merge_msg=`expr "z$1" : 'z-[^=]*=\(.*\)'`
+               have_message=t
+               ;;
+       -m|--m|--me|--mes|--mess|--messa|--messag|--message)
+               shift
+               case "$#" in
+               1)      usage ;;
+               esac
+               merge_msg="$1"
+               have_message=t
+               ;;
        -*)     usage ;;
        *)      break ;;
        esac
        shift
 done
 
-merge_msg="$1"
-shift
-head_arg="$1"
-head=$(git-rev-parse --verify "$1"^0) || usage
-shift
+# This could be traditional "merge <msg> HEAD <commit>..."  and the
+# way we can tell it is to see if the second token is HEAD, but some
+# people might have misused the interface and used a committish that
+# is the same as HEAD there instead.  Traditional format never would
+# have "-m" so it is an additional safety measure to check for it.
+
+if test -z "$have_message" &&
+       second_token=$(git-rev-parse --verify "$2^0" 2>/dev/null) &&
+       head_commit=$(git-rev-parse --verify "HEAD" 2>/dev/null) &&
+       test "$second_token" = "$head_commit"
+then
+       merge_msg="$1"
+       shift
+       head_arg="$1"
+       shift
+else
+       # We are invoked directly as the first-class UI.
+       head_arg=HEAD
+
+       # All the rest are the commits being merged; prepare
+       # the standard merge summary message to be appended to
+       # the given message.  If remote is invalid we will die
+       # later in the common codepath so we discard the error
+       # in this loop.
+       merge_name=$(for remote
+               do
+                       rh=$(git-rev-parse --verify "$remote"^0 2>/dev/null)
+                       if git show-ref -q --verify "refs/heads/$remote"
+                       then
+                               what=branch
+                       else
+                               what=commit
+                       fi
+                       echo "$rh               $what '$remote'"
+               done | git-fmt-merge-msg
+       )
+       merge_msg="${merge_msg:+$merge_msg$LF$LF}$merge_name"
+fi
+head=$(git-rev-parse --verify "$head_arg"^0) || usage
 
 # All the rest are remote heads
 test "$#" = 0 && usage ;# we need at least one remote head.