# [PATCH] git-merge -s theirs

3 messages from 2008-07-20 to 2008-07-28. Participants: Nanako Shiraishi, Junio C Hamano.
Thread: https://gitlist.dev/t/14544

## Nanako Shiraishi, 2008-07-20 10:21

Subject: [PATCH] git-merge -s theirs
Message-ID: <20080720192130.6117@nanako3.lavabit.com>
URL: https://gitlist.dev/e/20080720192130.6117%40nanako3.lavabit.com

```
Sometimes people wonder why "-s ours" strategy exists but "-s theirs" does
not.  The reason was explained on the mailing list recently:

  Quoting Junio C Hamano <gitster@pobox.com>:

  > One big problem "-s theirs" has, compared to the "reset to origin,
  > discarding or setting aside the failed history" is that your 'master'
  > history that your further development is based on will keep your failed
  > crap in it forever if you did "-s theirs".  Hopefully you will become a
  > better programmer over time, and you may eventually have something worth
  > sharing with the world near the tip of your master branch.  When that
  > happens, however, you _cannot_ offer your master branch to be pulled by
  > the upstream, as the wider world will not be interested in your earlier
  > mistakes at all.

This patch steals much code from "git-merge-resolve" to add "theirs"
strategy.  Its purpose is to always fail and suggest using the preferred
command "git reset --hard the-other-commit".

Signed-off-by: Nanako Shiraishi <nanako3@lavabit.com>
---
 Makefile            |    3 ++-
 builtin-merge.c     |    1 +
 git-merge-theirs.sh |   34 ++++++++++++++++++++++++++++++++++
 3 files changed, 37 insertions(+), 1 deletions(-)
 create mode 100755 git-merge-theirs.sh

diff --git a/Makefile b/Makefile
index 2b670d7..22f699a 100644
--- a/Makefile
+++ b/Makefile
@@ -240,6 +240,7 @@ SCRIPT_SH += git-lost-found.sh
 SCRIPT_SH += git-merge-octopus.sh
 SCRIPT_SH += git-merge-one-file.sh
 SCRIPT_SH += git-merge-resolve.sh
+SCRIPT_SH += git-merge-theirs.sh
 SCRIPT_SH += git-mergetool.sh
 SCRIPT_SH += git-parse-remote.sh
 SCRIPT_SH += git-pull.sh
@@ -1433,7 +1434,7 @@ check-docs::
 	do \
 		case "$$v" in \
 		git-merge-octopus | git-merge-ours | git-merge-recursive | \
-		git-merge-resolve | git-merge-subtree | \
+		git-merge-resolve | git-merge-subtree | git-merge-theirs | \
 		git-fsck-objects | git-init-db | \
 		git-?*--?* ) continue ;; \
 		esac ; \
diff --git a/builtin-merge.c b/builtin-merge.c
index edc6016..8ed815b 100644
--- a/builtin-merge.c
+++ b/builtin-merge.c
@@ -55,6 +55,7 @@ static struct strategy all_strategy[] = {
 	{ "octopus",    DEFAULT_OCTOPUS },
 	{ "resolve",    0 },
 	{ "ours",       NO_FAST_FORWARD | NO_TRIVIAL },
+	{ "theirs",     NO_FAST_FORWARD | NO_TRIVIAL },
 	{ "subtree",    NO_FAST_FORWARD | NO_TRIVIAL },
 };
 
diff --git a/git-merge-theirs.sh b/git-merge-theirs.sh
new file mode 100755
index 0000000..e228d2b
--- /dev/null
+++ b/git-merge-theirs.sh
@@ -0,0 +1,34 @@
+#!/bin/sh
+
+# The first parameters up to -- are merge bases; the rest are heads.
+bases= head= remotes= sep_seen=
+for arg
+do
+	case ",$sep_seen,$head,$arg," in
+	*,--,)
+		sep_seen=yes
+		;;
+	,yes,,*)
+		head=$arg
+		;;
+	,yes,*)
+		remotes="$remotes$arg "
+		;;
+	*)
+		bases="$bases$arg "
+		;;
+	esac
+done
+
+# Give up if we are given two or more remotes -- not handling octopus.
+case "$remotes" in
+?*' '?*)
+	exit 2 ;;
+esac
+
+echo "If you wanted to say the other history is better than your history," 
+echo "use 'git reset --hard $remotes' instead." 
+echo "If you want to keep a record of your failure, you can create a" 
+echo "new branch from the current HEAD before running the reset command." 
+
+exit 2
-- 
1.5.6.3

-- 
Nanako Shiraishi
http://ivory.ap.teacup.com/nanako3/

```

## Junio C Hamano, 2008-07-20 21:22

Subject: Re: [PATCH] git-merge -s theirs
Message-ID: <7vhcak45ez.fsf@gitster.siamese.dyndns.org>
URL: https://gitlist.dev/e/7vhcak45ez.fsf%40gitster.siamese.dyndns.org
In-Reply-To: <20080720192130.6117@nanako3.lavabit.com>

```
Nanako Shiraishi <nanako3@lavabit.com> writes:

> This patch steals much code from "git-merge-resolve" to add "theirs"
> strategy.  Its purpose is to always fail and suggest using the preferred
> command "git reset --hard the-other-commit".
> ...
> +echo "If you wanted to say the other history is better than your history," 
> +echo "use 'git reset --hard $remotes' instead." 
> +echo "If you want to keep a record of your failure, you can create a" 
> +echo "new branch from the current HEAD before running the reset command." 
> +
> +exit 2

That is certainly cute, but I do not like it for two reasons:

 - This advertizes "theirs" as available when you ask "git merge -s whoa",
   and then the user is told "don't use this stupid, go away".  That is
   not exactly a good diplomacy to earn friends.

 - The message gives a rather long hexdecimal string in its suggestion to
   run "git reset --hard".  This is not exactly your fault, though. The
   original refname the user gave to "git-merge" is not available to your
   strategy.

```

## Junio C Hamano, 2008-07-28 09:18

Subject: Re* [PATCH] git-merge -s theirs
Message-ID: <7vfxpus6xr.fsf_-_@gitster.siamese.dyndns.org>
URL: https://gitlist.dev/e/7vfxpus6xr.fsf_-_%40gitster.siamese.dyndns.org
In-Reply-To: <7vhcak45ez.fsf@gitster.siamese.dyndns.org>

```
Junio C Hamano <gitster@pobox.com> writes:

> Nanako Shiraishi <nanako3@lavabit.com> writes:
> ...
> That is certainly cute, but I do not like it for two reasons:
>
>  - This advertizes "theirs" as available when you ask "git merge -s whoa",
>    and then the user is told "don't use this stupid, go away".  That is
>    not exactly a good diplomacy to earn friends.
>
>  - The message gives a rather long hexdecimal string in its suggestion to
>    run "git reset --hard".  This is not exactly your fault, though. The
>    original refname the user gave to "git-merge" is not available to your
>    strategy.

This does not address the first point at all, but attempts to solve the
second issue.  Strategies now get the remote in the symbolic form
originally used on the command line.

All strategies know that they need to expect that the refs can be given
with arbitrary SHA-1 expressions, so this change should be safe.

 builtin-merge.c |   20 +++++++++++++++-----
 1 files changed, 15 insertions(+), 5 deletions(-)

diff --git a/builtin-merge.c b/builtin-merge.c
index e78fa18..1a9850f 100644
--- a/builtin-merge.c
+++ b/builtin-merge.c
@@ -22,6 +22,7 @@
 #include "log-tree.h"
 #include "color.h"
 #include "rerere.h"
+#include "decorate.h"
 
 #define DEFAULT_TWOHEAD (1<<0)
 #define DEFAULT_OCTOPUS (1<<1)
@@ -504,7 +505,7 @@ static void write_tree_trivial(unsigned char *sha1)
 }
 
 static int try_merge_strategy(const char *strategy, struct commit_list *common,
-			      const char *head_arg)
+			      const char *head_arg, struct decoration *symbolic)
 {
 	const char **args;
 	int i = 0, ret;
@@ -520,8 +521,12 @@ static int try_merge_strategy(const char *strategy, struct commit_list *common,
 		args[i++] = xstrdup(sha1_to_hex(j->item->object.sha1));
 	args[i++] = "--";
 	args[i++] = head_arg;
-	for (j = remoteheads; j; j = j->next)
-		args[i++] = xstrdup(sha1_to_hex(j->item->object.sha1));
+	for (j = remoteheads; j; j = j->next) {
+		char *name = lookup_decoration(symbolic, &j->item->object);
+		if (!name)
+			name = sha1_to_hex(j->item->object.sha1);
+		args[i++] = xstrdup(name);
+	}
 	args[i] = NULL;
 	ret = run_command_v_opt(args, RUN_GIT_CMD);
 	strbuf_release(&buf);
@@ -773,6 +778,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
 	struct commit_list *common = NULL;
 	const char *best_strategy = NULL, *wt_strategy = NULL;
 	struct commit_list **remotes = &remoteheads;
+	struct decoration symbolic_remote_head;
 
 	setup_work_tree();
 	if (unmerged_cache())
@@ -870,6 +876,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
 		strbuf_addf(&buf, " %s", argv[i]);
 	setenv("GIT_REFLOG_ACTION", buf.buf, 0);
 	strbuf_reset(&buf);
+	memset(&symbolic_remote_head, 0, sizeof(symbolic_remote_head));
 
 	for (i = 0; i < argc; i++) {
 		struct object *o;
@@ -877,6 +884,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
 		o = peel_to_type(argv[i], 0, NULL, OBJ_COMMIT);
 		if (!o)
 			die("%s - not something we can merge", argv[i]);
+		add_decoration(&symbolic_remote_head, o, xstrdup(argv[i]));
 		remotes = &commit_list_insert(lookup_commit(o->sha1),
 			remotes)->next;
 
@@ -1041,7 +1049,8 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
 		wt_strategy = use_strategies[i]->name;
 
 		ret = try_merge_strategy(use_strategies[i]->name,
-			common, head_arg);
+					 common, head_arg,
+					 &symbolic_remote_head);
 		if (!option_commit && !ret) {
 			merge_was_ok = 1;
 			/*
@@ -1105,7 +1114,8 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
 		restore_state();
 		printf("Using the %s to prepare resolving by hand.\n",
 			best_strategy);
-		try_merge_strategy(best_strategy, common, head_arg);
+		try_merge_strategy(best_strategy, common, head_arg,
+				   &symbolic_remote_head);
 	}
 
 	if (squash)

```
