# Re: Please undo "Use git-merge instead of git-resolve in

7 messages from 2005-09-22 to 2005-09-23. Participants: Jon Loeliger, Linus Torvalds, Daniel Barkalow, Junio C Hamano.
Thread: https://gitlist.dev/t/1917

## Jon Loeliger, 2005-09-22 19:12

Subject: Re: Please undo "Use git-merge instead of git-resolve in
Message-ID: <E1EIWUv-0004HR-F6@jdl.com>
URL: https://gitlist.dev/e/E1EIWUv-0004HR-F6%40jdl.com

```

Linus calmly explained again:
>
> The "origin" branch was already updated automatically if you used
> 
> 	git pull origin
> 
> However, if you used
> 
> 	git pull rsync:..../linus-2.6.git
> 
> then git would only have fetched the objects, and _not_ updated the 
> "origin" branch (because you didn't tell it about the "origin" branch). 
> 
> But you can trivially fix that by doing
> 
> 	git fetch origin
> 
> at this point, which will end up doing the equivalent of
> 
> 	git fetch rsync:..../linus-2.6.git master:origin
> 
> (depending on what the contents of your .git/remotes/origin are, of 
> course, the above is just an example).

This was a very helpful section for me.

> For example, it _may_ just contain something like
> 
>	URL: rsync:..../linus2.6.git
> 
> in which case there is no explicit heads specified. In that case, you 
> really should specify _which_ of the heads you want to pull, and what the 
> target should be. 

In fact it contained just the "rsync:...." bits.


> For example, you can do that with
>
>	git fetch linus master:linus
>
> which says: "fetch the branch 'master' from the repository described by 
> 'linus' (.git/remotes/linus) into _my_ branch 'linus'".

Just to be clear on the overloaded use of "linus" here,
let me rewrite that:

	git fetch foo master:bar

    which says: "fetch the branch 'master' from the repository described
    by 'foo' (.git/remotes/foo) into _my_ branch 'bar'".

Right?

> Now, you can specify that this is what you _always_ want to do, and
> actually set the branches in the ".git/remotes/linus" file explicitly.
> You can make your .git/remotes/linus file look like this instead:
>
>	URL: rsync:..../linus2.6.git
>	Pull: master:linus

OK.  I think I get it.  The concept you are trying to beat into
my head is essentially the difference between a "complete" and
an "incomplete" specifier.  If there is enough specification to
fetch and merge into a branch, you can.  And there are a few
different ways to do so:

    A) git fetch rsync:..../linus-2.6.git master:origin
or 
    B) git fetch linus master:linus
       with just the URL bits in the .git/remotes
or
    C)	git fetch linus
        with both URL and "Pull:" clauses in .git remotes
            URL: rsync:..../linus2.6.git
	    Pull: master:linus

If it is an incomplete specification (without branch names),
you just can't do the whole sheebang.  You have to stop after
fetching the objects.

And add "merging" in the "git pull" cases.

> Now, this is where "dirty" comes in. The merge will fail if you have 
> changed any files that the merge wants to modify. So do a

D'oh.  This is what bites me.  Some of those diffs that
come back to me in the linus tree are one that I originated
and sent up stream in the first place.  To get those to
wash-out with the merge, I will have had to have had those
committed in my branch, right?  Otherwise they just look
like dirty files -- never mind that they are (should be)
the exact same bits coming back at me.

> So do a
>
>	git diff --name-only HEAD
>
> to see if there are any changes, and commit them - or undo them - if so.
> Then try to pull again.

Ah hah.  OK.


I want to return to this for one last comment:

    > You can make your .git/remotes/linus file look like this instead:
    >
    >	URL: rsync:..../linus2.6.git
    >	Pull: master:linus

So, philosophically perhaps, there are several different
reasons for having branches within a repository.  One of
them is to track external repositories as indicated above.
But no-one (ie, no tool) currently constructs the .git/remotes
files to have that layout, right?  I mean, The One True editor
can, but there is no git or Cogito command that says to
construct the URL: and Pull: bits like that for the purposes
of establishing a "track branch", right?  Would it make sense
to have a "--tracking" flag added to branch creation that
trumped these bits up and promotes a simpler, or specific
purpose branch?

jdl

```

## Linus Torvalds, 2005-09-22 21:22

Subject: Re: Please undo "Use git-merge instead of git-resolve in
Message-ID: <Pine.LNX.4.58.0509221413400.2553@g5.osdl.org>
URL: https://gitlist.dev/e/Pine.LNX.4.58.0509221413400.2553%40g5.osdl.org
In-Reply-To: <E1EIWUv-0004HR-F6@jdl.com>

```


On Thu, 22 Sep 2005, Jon Loeliger wrote:
>
> > For example, you can do that with
> >
> >	git fetch linus master:linus
> >
> > which says: "fetch the branch 'master' from the repository described by 
> > 'linus' (.git/remotes/linus) into _my_ branch 'linus'".
> 
> Just to be clear on the overloaded use of "linus" here,
> let me rewrite that:
> 
> 	git fetch foo master:bar
> 
>     which says: "fetch the branch 'master' from the repository described
>     by 'foo' (.git/remotes/foo) into _my_ branch 'bar'".
> 
> Right?

Right.

> OK.  I think I get it.  The concept you are trying to beat into
> my head is essentially the difference between a "complete" and
> an "incomplete" specifier.  If there is enough specification to
> fetch and merge into a branch, you can.  And there are a few
> different ways to do so:
> 
>     A) git fetch rsync:..../linus-2.6.git master:origin
> or 
>     B) git fetch linus master:linus
>        with just the URL bits in the .git/remotes
> or
>     C)	git fetch linus
>         with both URL and "Pull:" clauses in .git remotes
>             URL: rsync:..../linus2.6.git
> 	    Pull: master:linus

Absolutely.

Note that you can also override, so let's say that you have _both_ the
"URL:" and the "Pull:" line in your "remotes" file, the "pull" line is 
still just a default, so you could do

	git fetch linus other:myother

and it would now use the URL line, but since you specified the branch by
hand, it would ignore the default branch information, and instead fetch
the "other" branch from the remote site into the "myother" local branch.

> > Now, this is where "dirty" comes in. The merge will fail if you have 
> > changed any files that the merge wants to modify. So do a
> 
> D'oh.  This is what bites me.  Some of those diffs that
> come back to me in the linus tree are one that I originated
> and sent up stream in the first place.  To get those to
> wash-out with the merge, I will have had to have had those
> committed in my branch, right?

Yes. Then git will merge them for you automatically (if they are 
identical), or may ask you to fix up any merge rejects (if there are 
clashes). 

Now, the fixing up any merges is pretty much exactly the same as under 
CVS - you'll get the same "<<<<" "====" ">>>>" markers.

>			  Otherwise they just look
> like dirty files -- never mind that they are (should be)
> the exact same bits coming back at me.

Right, but git doesn't know, and is too lazy to check. 

I _considered_ allowing a dirty file that happened to match the end 
result, but I never felt it was worth the complexity. It's nasty. And if 
it doesn't match, you really can't merge, because it's too dangerous to 
overwrite the users changes (even if you use some three-way merge and 
leave the rejects there).

> I want to return to this for one last comment:
> 
>     > You can make your .git/remotes/linus file look like this instead:
>     >
>     >	URL: rsync:..../linus2.6.git
>     >	Pull: master:linus
> 
> So, philosophically perhaps, there are several different
> reasons for having branches within a repository.  One of
> them is to track external repositories as indicated above.

Yes.

> But no-one (ie, no tool) currently constructs the .git/remotes
> files to have that layout, right?

The "git clone" thing will construct the original "origin" file to that 
layout. That's fairly recent, though.

And I think "cg-branch" will do it these days - and that's very much the
intent.  Havign porcelain on top of git that hides this thing so that you
don't have to edit configuration files by hand.

(Don't get me wrong: I think it's wonderful to have ASCII configuration 
files that you _can_ edit by hand, and it's the UNIX way of doing things, 
but I also think it's great to have front-end tools that allow doing these 
things without even having to understand the config file syntax etc).

		Linus

```

## Linus Torvalds, 2005-09-22 21:37

Subject: Re: Please undo "Use git-merge instead of git-resolve in
Message-ID: <Pine.LNX.4.58.0509221427520.2553@g5.osdl.org>
URL: https://gitlist.dev/e/Pine.LNX.4.58.0509221427520.2553%40g5.osdl.org
In-Reply-To: <Pine.LNX.4.58.0509221413400.2553@g5.osdl.org>

```


On Thu, 22 Sep 2005, Linus Torvalds wrote:
> 
> Now, the fixing up any merges is pretty much exactly the same as under 
> CVS - you'll get the same "<<<<" "====" ">>>>" markers.

I should have continued this. 

What you do is you just edit the end result to be what it should be 
(exactly as under CVS), and then you do "git commit --all" to commit the 
manual merge.

NOTE NOTE NOTE! This is one case where if you had dirty state in your tree
before the merge, that you need to be careful. In that case you obviously
must NOT use "--all", since that will commit all the dirty state - both
your old dirty state _and_ your manual merge resolve. So if you had other 
changes in your tree that you don't want to commit, you need to do

	git commit <list manually merged files individually here>

so that it doesn't commit anything else. 

Oh. And while preparing the merge, you can use

	git diff

to see what the manual part was: the automated part of the merge will have
updated index for the automatic side, so this will _not_ show the part 
of the merge that was done automatically for you.

Or, of you want to see _everything_ the merge has done, just do

	git diff HEAD

to see what the _total_ diff from your pre-merge head was to what is now
in your tree. But that will be the diff for what you're merging - so it
can be _huge_ if you're pulling my tree and merging everything I've
accepted over the last week or two.

And if the merge ends up being too complex, and you decide that you need 
help and want to undo the partial merge entirely and not even try to fix 
it up, do

	git reset --hard

which will roll back the index and the working tree to your old HEAD (BUT 
LOOK OUT! IT WILL ALSO DESTROY ANY DIRTY STATE YOU HAD BEFORE THE MERGE!).

Basically: having dirty state in your tree and then ending up having to do 
a manual merge is a big pain. Not worth it. I just keep really small dirty 
stuff so that I don't mind blowing it away if I need to.

		Linus

```

## Daniel Barkalow, 2005-09-22 21:57

Subject: Re: Please undo "Use git-merge instead of git-resolve in
Message-ID: <Pine.LNX.4.63.0509221747340.23242@iabervon.org>
URL: https://gitlist.dev/e/Pine.LNX.4.63.0509221747340.23242%40iabervon.org
In-Reply-To: <Pine.LNX.4.58.0509221427520.2553@g5.osdl.org>

```
On Thu, 22 Sep 2005, Linus Torvalds wrote:

> Basically: having dirty state in your tree and then ending up having to do 
> a manual merge is a big pain. Not worth it. I just keep really small dirty 
> stuff so that I don't mind blowing it away if I need to.

Would it be worthwhile to have a flag to make git-read-tree abort rather 
than making a mess if you have any dirty state and the merge isn't 
completely automatic? It's certainly easy enough to write.

	-Daniel
*This .sig left intentionally blank*

```

## Linus Torvalds, 2005-09-22 22:05

Subject: Re: Please undo "Use git-merge instead of git-resolve in
Message-ID: <Pine.LNX.4.58.0509221500150.2553@g5.osdl.org>
URL: https://gitlist.dev/e/Pine.LNX.4.58.0509221500150.2553%40g5.osdl.org
In-Reply-To: <Pine.LNX.4.63.0509221747340.23242@iabervon.org>

```


On Thu, 22 Sep 2005, Daniel Barkalow wrote:
> 
> Would it be worthwhile to have a flag to make git-read-tree abort rather 
> than making a mess if you have any dirty state and the merge isn't 
> completely automatic? It's certainly easy enough to write.

I don't think it would be wrong, necessarily.

On the other hand, it might be easier to just instead do a 

	git diff HEAD > .git/pre-merge-diff

and let it go at that. If the merge ends up being nasty, you can then just 
do

	git reset --hard
	git-apply .git/pre-merge-diff

or something.

I dunno. This is not something that has caused me a lot of headache. I 
certainly _hope_ that people generally don't keep a lot of dirty state 
around: I do it for truly small stuff that I don't care about.

Let's face it - if I cared about it, I'd have committed it (possibly to
another branch). It's not like that's hard. So the dirty stuff really does 
tend to be only trivial things.

		Linus

```

## Junio C Hamano, 2005-09-23 08:33

Subject: [PATCH] Fix overzealous cleanliness check in git-merge
Message-ID: <7vslvwfajf.fsf_-_@assigned-by-dhcp.cox.net>
URL: https://gitlist.dev/e/7vslvwfajf.fsf_-_%40assigned-by-dhcp.cox.net
In-Reply-To: <Pine.LNX.4.58.0509221500150.2553@g5.osdl.org>

```
Being able to try multiple strategies and automatically picking one
that seems to give less conflicting result may or may not much sense
in practice.  At least that should not force normal use case to
additionally require the working tree to be fully clean.  As Linus
shouted, local changes do not matter unless they interfere with the
merge.

This commit changes git-merge not to require a clean working tree.
Only when we will iterate through more than one merge strategies,
local changes are stashed away before trying the first merge, and
restored before second and later merges are attempted.

The index file must be in sync with HEAD in any case -- otherwise the
merge result would contain changes since HEAD that was done locally
and registered in the index.  This check is already enforced by
three-way read-tree existing merge strategies use, but is done here as
a safeguard as well.

Signed-off-by: Junio C Hamano <junkio@cox.net>

---

 Taking hint from your message, here is an attempt to fix the
 'incredibly broken' git-merge.  This does not make git-pull
 use it yet.

 git-merge.sh |   65 ++++++++++++++++++++++++++++++++++++++++++++--------------
 1 files changed, 49 insertions(+), 16 deletions(-)

abfefa19cf56a312d571ea36a491152ac7aef657
diff --git a/git-merge.sh b/git-merge.sh
--- a/git-merge.sh
+++ b/git-merge.sh
@@ -18,8 +18,19 @@ all_strategies='recursive octopus resolv
 default_strategies='resolve octopus'
 use_strategies=
 
-dropheads() {
-	rm -f -- "$GIT_DIR/MERGE_HEAD" || exit 1
+dropsave() {
+	rm -f -- "$GIT_DIR/MERGE_HEAD" \
+		 "$GIT_DIR/MERGE_SAVE" || exit 1
+}
+
+savestate() {
+	git diff -r -z --name-only $head | cpio -0 -o >"$GIR_DIR/MERGE_SAVE"
+}
+
+restorestate() {
+	git reset --hard $head
+	cpio -iuv <"$GIT_DIR/MERGE_SAVE"
+	git-update-index --refresh >/dev/null
 }
 
 summary() {
@@ -92,7 +103,7 @@ case "$#,$common" in
 	# If head can reach all the merge then we are up to date.
 	# but first the most common case of merging one remote
 	echo "Already up-to-date. Yeeah!"
-	dropheads
+	dropsave
 	exit 0
 	;;
 1,"$head")
@@ -102,7 +113,7 @@ case "$#,$common" in
 	git-read-tree -u -m $head "$1" || exit 1
 	git-rev-parse --verify "$1^0" > "$GIT_DIR/HEAD"
 	summary "$1"
-	dropheads
+	dropsave
 	exit 0
 	;;
 1,*)
@@ -124,29 +135,51 @@ case "$#,$common" in
 	if test "$up_to_date" = t
 	then
 		echo "Already up-to-date. Yeeah!"
-		dropheads
+		dropsave
 		exit 0
 	fi
 	;;
 esac
 
-# At this point we need a real merge.  Require that the tree matches
-# exactly our head.
 
-git-update-index --refresh &&
-test '' = "`git-diff-index --cached --name-only $head`" || {
-	die "Need real merge but the working tree has local changes."
-}
+# At this point, we need a real merge.  No matter what strategy
+# we use, it would operate on the index, possibly affecting the
+# working tree, and when resolved cleanly, have the desired tree
+# in the index -- this means that the index must be in sync with
+# the $head commit.
+files=$(git-diff-index --cached --name-only $head) || exit
+if [ "$files" ]; then
+   echo >&2 "Dirty index: cannot merge (dirty: $files)"
+   exit 1
+fi
+
+case "$use_strategies" in
+?*' '?*)
+    # Stash away the local changes so that we can try more than one.
+    savestate
+    single_strategy=no
+    ;;
+*)
+    single_strategy=yes
+    ;;
+esac
 
 result_tree= best_cnt=-1 best_strategy= wt_strategy=
 for strategy in $use_strategies
 do
     test "$wt_strategy" = '' || {
 	echo "Rewinding the tree to pristine..."
-	git reset --hard $head
+	restorestate
     }
-    echo "Trying merge strategy $strategy..."
+    case "$single_strategy" in
+    no)
+	echo "Trying merge strategy $strategy..."
+	;;
+    esac
+
+    # Remember which strategy left the state in the working tree
     wt_strategy=$strategy
+
     git-merge-$strategy $common -- $head "$@" || {
 
 	# The backend exits with 1 when conflicts are left to be resolved,
@@ -185,14 +218,14 @@ then
     echo "Committed merge $result_commit, made by $wt_strategy."
     echo $result_commit >"$GIT_DIR/HEAD"
     summary $result_commit
-    dropheads
+    dropsave
     exit 0
 fi
 
 # Pick the result from the best strategy and have the user fix it up.
 case "$best_strategy" in
 '')
-	git reset --hard $head
+	restorestate
 	die "No merge strategy handled the merge."
 	;;
 "$wt_strategy")
@@ -200,7 +233,7 @@ case "$best_strategy" in
 	;;
 *)
 	echo "Rewinding the tree to pristine..."
-	git reset --hard $head
+	restorestate
 	echo "Using the $best_strategy to prepare resolving by hand."
 	git-merge-$best_strategy $common -- $head "$@"
 	;;

```

## Junio C Hamano, 2005-09-23 09:01

Subject: [PATCH] Use git-merge in git-pull (second try).
Message-ID: <7vr7bgdup0.fsf@assigned-by-dhcp.cox.net>
URL: https://gitlist.dev/e/7vr7bgdup0.fsf%40assigned-by-dhcp.cox.net
In-Reply-To: <Pine.LNX.4.58.0509221500150.2553@g5.osdl.org>

```
This again makes git-pull to use git-merge, so that different merge
strategy can be specified from the command line.  Without explicit
strategy parameter, it defaults to git-merge-resolve if only one
remote is pulled, and git-merge-octopus otherwise, to keep the
default behaviour of the command the same as the original.

Also this brings another usability measure: -n flag from the command
line, if given, is passed to git-merge to prevent it from running the
diffstat at the end of the merge.

Signed-off-by: Junio C Hamano <junkio@cox.net>

---

 I tested this at least once with a dirty working tree ;-).  The
 main difference from the one that was backed out is that only
 one strategy is used by default -- this is to avoid any
 'stashing away old states' done on the git-merge side.

 git-pull.sh |   48 ++++++++++++++++++++++++++++++++++++++++++++----
 1 files changed, 44 insertions(+), 4 deletions(-)

9c078a16523a2aae224a99e70f41eeb3d05a470c
diff --git a/git-pull.sh b/git-pull.sh
--- a/git-pull.sh
+++ b/git-pull.sh
@@ -6,6 +6,38 @@
 
 . git-sh-setup || die "Not a git archive"
 
+usage () {
+    die "git pull [-n] [-s strategy]... <repo> <head>..."
+}
+
+strategy_args= no_summary=
+while case "$#,$1" in 0) break ;; *,-*) ;; *) break ;; esac
+do
+	case "$1" in
+	-n|--n|--no|--no-|--no-s|--no-su|--no-sum|--no-summ|\
+		--no-summa|--no-summar|--no-summary)
+		no_summary=-n ;;
+	-s=*|--s=*|--st=*|--str=*|--stra=*|--strat=*|--strate=*|\
+		--strateg=*|--strategy=*|\
+	-s|--s|--st|--str|--stra|--strat|--strate|--strateg|--strategy)
+		case "$#,$1" in
+		*,*=*)
+			strategy=`expr "$1" : '-[^=]*=\(.*\)'` ;;
+		1,*)
+			usage ;;
+		*)
+			strategy="$2"
+			shift ;;
+		esac
+		strategy_args="${strategy_args}-s $strategy "
+		;;
+	-*)
+		usage
+		;;
+	esac
+	shift
+done
+
 orig_head=$(cat "$GIT_DIR/HEAD") || die "Pulling into a black hole?"
 git-fetch --update-head-ok "$@" || exit 1
 
@@ -31,11 +63,19 @@ case "$merge_head" in
 	echo >&2 "No changes."
 	exit 0
 	;;
-*' '?*)
-	echo >&2 "Pulling more than one heads; making an Octopus."
-	exec git-octopus
+?*' '?*)
+	strategy_default_args='-s octopus'
+	;;
+*)
+	strategy_default_args='-s resolve'
+	;;
+esac
+
+case "$strategy_args" in
+'')
+	strategy_args=$strategy_default_args
 	;;
 esac
 
 merge_name=$(git-fmt-merge-msg <"$GIT_DIR/FETCH_HEAD")
-git-resolve "$(cat "$GIT_DIR"/HEAD)" $merge_head "$merge_name"
+git-merge $no_summary $strategy_args "$merge_name" HEAD $merge_head

```
