git@vger.kernel.org mailing list mirror (one of many)
 help / color / mirror / code / Atom feed
* Updated multi-head downloads and $GIT_DIR/remotes/ support
@ 2005-08-20 18:13 Junio C Hamano
  2005-08-20 18:22 ` [PATCH] Start adding the " Junio C Hamano
                   ` (5 more replies)
  0 siblings, 6 replies; 7+ messages in thread
From: Junio C Hamano @ 2005-08-20 18:13 UTC (permalink / raw
  To: git

Now I think all the pieces are glued together.  I'll send the
following patches, which are already in the proposed updates
branch.

I sent an early WIP for some of them, but the patches are
reorganized for easier review and applies on top of the current
"master" branch.

This series consists of the following:

    Start adding the $GIT_DIR/remotes/ support.
    Multi-head fetch.
    Retire git-parse-remote.
    Infamous 'octopus merge'
    Make "git pull" and "git fetch" default to origin
    Use .git/remote/origin, not .git/branches/origin.

The issues I discussed in "Multi-head fetches, pulls, and a King
Ghidorah" are addressed there, and the examples in "MyGITDay"
message I sent earlier should work with these patches.  I'll
work on adding some documentation, maybe in howto or tutorial
format, over the weekend.

-jc

^ permalink raw reply	[flat|nested] 7+ messages in thread

* [PATCH] Start adding the $GIT_DIR/remotes/ support.
  2005-08-20 18:13 Updated multi-head downloads and $GIT_DIR/remotes/ support Junio C Hamano
@ 2005-08-20 18:22 ` Junio C Hamano
  2005-08-20 18:25 ` [PATCH] Multi-head fetch Junio C Hamano
                   ` (4 subsequent siblings)
  5 siblings, 0 replies; 7+ messages in thread
From: Junio C Hamano @ 2005-08-20 18:22 UTC (permalink / raw
  To: git

All the necessary parsing code is in git-parse-remote-script;
update git-push-script to use it.

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

---

    ** sorry I made a mistake of letting git send-email to
    ** send nonsense messages ...

 Makefile                |    2 -
 git-parse-remote-script |  144 +++++++++++++++++++++++++++++++++++++++++++++++
 git-push-script         |   28 ++-------
 3 files changed, 151 insertions(+), 23 deletions(-)
 create mode 100755 git-parse-remote-script

284ba9655aedbdaaa897fdcc6aabae97de8d99d1
diff --git a/Makefile b/Makefile
--- a/Makefile
+++ b/Makefile
@@ -64,7 +64,7 @@ SCRIPTS=git git-apply-patch-script git-m
 	git-reset-script git-add-script git-checkout-script git-clone-script \
 	gitk git-cherry git-rebase-script git-relink-script git-repack-script \
 	git-format-patch-script git-sh-setup-script git-push-script \
-	git-branch-script git-parse-remote git-verify-tag-script \
+	git-branch-script git-parse-remote git-parse-remote-script git-verify-tag-script \
 	git-ls-remote-script git-clone-dumb-http git-rename-script \
 	git-request-pull-script git-bisect-script
 
diff --git a/git-parse-remote-script b/git-parse-remote-script
new file mode 100755
--- /dev/null
+++ b/git-parse-remote-script
@@ -0,0 +1,144 @@
+#!/bin/sh
+
+. git-sh-setup-script || die "Not a git archive"
+
+get_data_source () {
+	case "$1" in
+	*/*)
+		# Not so fast.  This could be the partial URL shorthand...
+		token=$(expr "$1" : '\([^/]*\)/')
+		remainder=$(expr "$1" : '[^/]*/\(.*\)')
+		if test -f "$GIT_DIR/branches/$token"
+		then
+			echo branches-partial
+		else
+			echo ''
+		fi
+		;;
+	*)
+		if test -f "$GIT_DIR/remotes/$1"
+		then
+			echo remotes
+		elif test -f "$GIT_DIR/branches/$1"
+		then
+			echo branches
+		else
+			echo ''
+		fi ;;
+	esac
+}
+
+get_remote_url () {
+	data_source=$(get_data_source "$1")
+	case "$data_source" in
+	'')
+		echo "$1" ;;
+	remotes)
+		sed -ne '/^URL: */{
+			s///p
+			q
+		}' "$GIT_DIR/remotes/$1" ;;
+	branches)
+		sed -e 's/#.*//' "$GIT_DIR/branches/$1" ;;
+	branches-partial)
+		token=$(expr "$1" : '\([^/]*\)/')
+		remainder=$(expr "$1" : '[^/]*/\(.*\)')
+		url=$(sed -e 's/#.*//' "$GIT_DIR/branches/$token")
+		echo "$url/$remainder"
+		;;
+	*)
+		die "internal error: get-remote-url $1" ;;
+	esac
+}
+
+get_remote_default_refs_for_push () {
+	data_source=$(get_data_source "$1")
+	case "$data_source" in
+	'' | branches | branches-partial)
+		;; # no default push mapping, just send matching refs.
+	remotes)
+		sed -ne '/^Push: */{
+			s///p
+		}' "$GIT_DIR/remotes/$1" ;;
+	*)
+		die "internal error: get-remote-default-ref-for-push $1" ;;
+	esac
+}
+
+# Subroutine to canonicalize remote:local notation
+canon_refs_list_for_fetch () {
+	for ref
+	do
+		expr "$ref" : '.*:' >/dev/null || ref="${ref}:"
+		remote=$(expr "$ref" : '\([^:]*\):')
+		local=$(expr "$ref" : '[^:]*:\(.*\)')
+		case "$remote" in
+		'') remote=HEAD ;;
+		*) remote="refs/heads/$remote" ;;
+		esac
+		case "$local" in
+		'') local= ;;
+		*) local="refs/heads/$local" ;;
+		esac
+		echo "${remote}:${local}"
+	done
+}
+
+# Returns list of src: (no store), or src:dst (store)
+get_remote_default_refs_for_fetch () {
+	data_source=$(get_data_source "$1")
+	case "$data_source" in
+	'' | branches-partial)
+		echo "HEAD:" ;;
+	branches)
+		remote_branch=$(sed -ne '/#/s/.*#//p' "$GIT_DIR/branches/$1")
+		case "$remote_branch" in '') remote_branch=master ;; esac
+		echo "refs/heads/${remote_branch}:refs/heads/$1"
+		;;
+	remotes)
+		canon_refs_list_for_fetch $(sed -ne '/^Pull: */{
+						s///p
+					}' "$GIT_DIR/remotes/$1")
+		;;
+	*)
+		die "internal error: get-remote-default-ref-for-push $1" ;;
+	esac
+}
+
+get_remote_refs_for_push () {
+	case "$#" in
+	0) die "internal error: get-remote-refs-for-push." ;;
+	1) get_remote_default_refs_for_push "$@" ;;
+	*) shift; echo "$@" ;;
+	esac
+}
+
+get_remote_refs_for_fetch () {
+	case "$#" in
+	0)
+	    die "internal error: get-remote-refs-for-fetch." ;;
+	1)
+	    get_remote_default_refs_for_fetch "$@" ;;
+	*)
+	    shift
+	    tag_just_seen=
+	    for ref
+	    do
+		if test "$tag_just_seen"
+		then
+		    echo "refs/tags/${ref}:refs/tags/${ref}"
+		    tag_just_seen=
+		    continue
+		else
+		    case "$ref" in
+		    tag)
+		        tag_just_seen=yes
+			continue
+			;;
+		    esac
+		fi
+	        canon_refs_list_for_fetch "$ref"
+	    done
+	    ;;
+	esac
+}
diff --git a/git-push-script b/git-push-script
--- a/git-push-script
+++ b/git-push-script
@@ -20,8 +20,6 @@ do
 	-*)
 		die "Unknown parameter $1" ;;
         *)
-		remote="$1"
-		shift
 		set x "$@"
 		shift
 		break ;;
@@ -29,27 +27,13 @@ do
 	shift
 done
 
-case "$remote" in
-*:* | /* | ../* | ./* )
-	# An URL, host:/path/to/git, absolute and relative paths.
-	;;
-* )
-	# Shorthand
-	if expr "$remote" : '..*/..*' >/dev/null
-	then
-		# a short-hand followed by a trailing path
-		shorthand=$(expr "$remote" : '\([^/]*\)')
-		remainder=$(expr "$remote" : '[^/]*\(/.*\)$')
-	else
-		shorthand="$remote"
-		remainder=
-	fi
-	remote=$(sed -e 's/#.*//' "$GIT_DIR/branches/$remote") &&
-	expr "$remote" : '..*:' >/dev/null &&
-	remote="$remote$remainder" ||
-	die "Cannot parse remote $remote"
-	;;
+. git-parse-remote-script
+remote=$(get_remote_url "$@")
+case "$has_all" in
+--all) set x ;;
+'')    set x $(get_remote_refs_for_push "$@") ;;
 esac
+shift
 
 case "$remote" in
 http://* | https://* | git://* | rsync://* )

^ permalink raw reply	[flat|nested] 7+ messages in thread

* [PATCH] Multi-head fetch.
  2005-08-20 18:13 Updated multi-head downloads and $GIT_DIR/remotes/ support Junio C Hamano
  2005-08-20 18:22 ` [PATCH] Start adding the " Junio C Hamano
@ 2005-08-20 18:25 ` Junio C Hamano
  2005-08-20 18:25 ` [PATCH] Retire git-parse-remote Junio C Hamano
                   ` (3 subsequent siblings)
  5 siblings, 0 replies; 7+ messages in thread
From: Junio C Hamano @ 2005-08-20 18:25 UTC (permalink / raw
  To: git

Traditionally, fetch takes these forms:

    $ git fetch <remote>
    $ git fetch <remote> <head>
    $ git fetch <remote> tag <tag>

This patch updates it to take

    $ git fetch <remote> <refspec>...

where:

    - A <refspec> of form "<src>:<dst>" is to fetch the objects
      needed for the remote ref that matches <src>, and if <dst>
      is not empty, store it as a local <dst>.

    - "tag" followed by <next> is just an old way of saying
      "refs/tags/<next>:refs/tags/<next>"; this mimics the
      current behaviour of the third form above and means "fetch
      that tag and store it under the same name".

    - A single token <refspec> without colon is a shorthand for
      "<refspec>:"  That is, "fetch that ref but do not store
      anywhere".

    - when there is no <refspec> specified

      - if <remote> is the name of a file under $GIT_DIR/remotes/
	(i.e. a new-style shorthand), then it is the same as giving
	the <refspec>s listed on Pull: line in that file.

      - if <remote> is the name of a file under $GIT_DIR/branches/
	(i.e. an old-style shorthand, without trailing path), then it
	is the same as giving a single <refspec>
	"<remote-name>:refs/heads/<remote>" on the command line, where
	<remote-name> is the remote branch name (defaults to HEAD, but
	can be overridden by .git/branches/<remote> file having the
	URL fragment notation).  That is, "fetch that branch head and
	store it in refs/heads/<remote>".

      - otherwise, it is the same as giving a single <refspec>
        that is "HEAD:".

The SHA1 object names of fetched refs are stored in FETCH_HEAD,
one name per line, with a comment to describe where it came from.
This is later used by "git resolve" and "git octopus".

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

---

 git-fetch-script |  193 ++++++++++++++++++++++++++++++++++++++++++------------
 1 files changed, 149 insertions(+), 44 deletions(-)

d947289005049c67f1dded517a1a6a8843fcf4a3
diff --git a/git-fetch-script b/git-fetch-script
--- a/git-fetch-script
+++ b/git-fetch-script
@@ -1,54 +1,159 @@
 #!/bin/sh
 #
 . git-sh-setup-script || die "Not a git archive"
-. git-parse-remote "$@"
-merge_repo="$_remote_repo"
-merge_head="$_remote_head"
-merge_store="$_remote_store"
-
-TMP_HEAD="$GIT_DIR/TMP_HEAD"
-
-case "$merge_repo" in
-http://* | https://*)
-        if [ -n "$GIT_SSL_NO_VERIFY" ]; then
-            curl_extra_args="-k"
-        fi
-	_x40='[0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f]' &&
-	_x40="$_x40$_x40$_x40$_x40$_x40$_x40$_x40$_x40" &&
-	head=$(curl -nsf $curl_extra_args "$merge_repo/$merge_head") &&
-	expr "$head" : "$_x40\$" >/dev/null || {
-		echo >&2 "Failed to fetch $merge_head from $merge_repo"
-	        exit 1
-	}
-	echo Fetching "$merge_head" using http
-	git-http-pull -v -a "$head" "$merge_repo/" || exit
-	;;
-rsync://*)
-	rsync -L "$merge_repo/$merge_head" "$TMP_HEAD" || exit 1
-	head=$(git-rev-parse TMP_HEAD)
-	rm -f "$TMP_HEAD"
-	rsync -avz --ignore-existing "$merge_repo/objects/" "$GIT_OBJECT_DIRECTORY/"
-	;;
+. git-parse-remote-script
+_x40='[0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f]'
+_x40="$_x40$_x40$_x40$_x40$_x40$_x40$_x40$_x40"
+
+append=
+case "$#" in
+0)
+	die "Where do you want to fetch from?" ;;
 *)
-	head=$(git-fetch-pack "$merge_repo" "$merge_head")
-	if h=`expr "$head" : '\([^ ][^ ]*\) '`
+	case "$1" in
+	-a|--a|--ap|--app|--appe|--appen|--append)
+		append=t
+		shift ;;
+	esac
+esac
+remote_nick="$1"
+remote=$(get_remote_url "$@")
+refs=
+rref=
+rsync_slurped_objects=
+
+if test "" = "$append"
+then
+	: >$GIT_DIR/FETCH_HEAD
+fi
+
+append_fetch_head () {
+    head_="$1"
+    remote_="$2"
+    remote_name_="$3"
+    remote_nick_="$4"
+    local_name_="$5"
+
+    # 2.6.11-tree tag would not be happy to be fed to resolve.
+    if git-cat-file commit "$head_" >/dev/null 2>&1
+    then
+	head_=$(git-rev-parse --verify "$head_^0") || exit
+	note_="$head_	$remote_name_ from $remote_nick_"
+	echo "$note_" >>$GIT_DIR/FETCH_HEAD
+	echo >&2 "* committish: $note_"
+    else
+	echo >&2 "* non-commit: $note_"
+    fi
+    if test "$local_name_" != ""
+    then
+	# We are storing the head locally.  Make sure that it is
+	# a fast forward (aka "reverse push").
+	fast_forward_local "$local_name_" "$head_" "$remote_" "$remote_name_"
+    fi
+}
+
+fast_forward_local () {
+    case "$1" in
+    refs/tags/*)
+	# Tags need not be pointing at commits so there
+	# is no way to guarantee "fast-forward" anyway.
+	echo "$2" >"$GIT_DIR/$1" ;;
+    refs/heads/*)
+	# NEEDSWORK: use the same cmpxchg protocol here.
+	echo "$2" >"$GIT_DIR/$1.lock"
+	if test -f "$GIT_DIR/$1"
 	then
-	    head=$h
+	    local=$(git-rev-parse --verify "$1^0") &&
+	    mb=$(git-merge-base "$local" "$2") &&
+	    case "$2,$mb" in
+	    $local,*)
+		echo >&2 "* $1: same as $4"
+		echo >&2 "  from $3"
+		;;
+	    *,$local)
+		echo >&2 "* $1: fast forward to $4"
+		echo >&2 "  from $3"
+		;;
+	    *)
+		false
+		;;
+	    esac || {
+		mv "$GIT_DIR/$1.lock" "$GIT_DIR/$1.remote"
+		echo >&2 "* $1: does not fast forward to $4"
+		echo >&2 "  from $3; leaving it in '$1.remote'"
+	    }
+	else
+		echo >&2 "* $1: storing $4"
+		echo >&2 "  from $3."
 	fi
+	test -f "$GIT_DIR/$1.lock" &&
+	    mv "$GIT_DIR/$1.lock" "$GIT_DIR/$1"
 	;;
-esac || exit 1
-
-git-rev-parse --verify "$head" > /dev/null || exit 1
+    esac
+}
 
-case "$merge_store" in
-'')
+for ref in $(get_remote_refs_for_fetch "$@")
+do
+    refs="$refs $ref"
+
+    # These are relative path from $GIT_DIR, typically starting at refs/
+    # but may be HEAD
+    remote_name=$(expr "$ref" : '\([^:]*\):')
+    local_name=$(expr "$ref" : '[^:]*:\(.*\)')
+
+    rref="$rref $remote_name"
+
+    # There are transports that can fetch only one head at a time...
+    case "$remote" in
+    http://* | https://*)
+	if [ -n "$GIT_SSL_NO_VERIFY" ]; then
+	    curl_extra_args="-k"
+	fi
+	head=$(curl -nsf $curl_extra_args "$remote/$remote_name") &&
+	expr "$head" : "$_x40\$" >/dev/null ||
+	    die "Failed to fetch $remote_name from $remote"
+	echo Fetching "$remote_name from $remote" using http
+	git-http-pull -v -a "$head" "$remote/" || exit
 	;;
+    rsync://*)
+	TMP_HEAD="$GIT_DIR/TMP_HEAD"
+	rsync -L "$remote/$remote_name" "$TMP_HEAD" || exit 1
+	head=$(git-rev-parse TMP_HEAD)
+	rm -f "$TMP_HEAD"
+	test "$rsync_slurped_objects" || {
+	    rsync -avz --ignore-existing "$remote/objects/" \
+		"$GIT_OBJECT_DIRECTORY/" || exit
+	    rsync_slurped_objects=t
+	}
+	;;
+    *)
+	# We will do git native transport with just one call later.
+	continue ;;
+    esac
+
+    append_fetch_head "$head" "$remote" "$remote_name" "$remote_nick" "$local_name"
+
+done
+
+case "$remote" in
+http://* | https://* | rsync://* )
+    ;; # we are already done.
 *)
-	echo "$head" > "$GIT_DIR/$merge_store"
-esac &&
-
-# FETCH_HEAD is fed to git-resolve-script which will eventually be
-# passed to git-commit-tree as one of the parents.  Make sure we do
-# not give a tag object ID.
-
-git-rev-parse "$head^0" >"$GIT_DIR/FETCH_HEAD"
+    git-fetch-pack "$remote" $rref |
+    while read sha1 remote_name
+    do
+	found=
+	for ref in $refs
+	do
+	    case "$ref" in
+	    $remote_name:*)
+		found="$ref"
+		break ;;
+	    esac
+	done
+
+	local_name=$(expr "$found" : '[^:]*:\(.*\)')
+        append_fetch_head "$sha1" "$remote" "$remote_name" "$remote_nick" "$local_name"
+    done
+    ;;
+esac

^ permalink raw reply	[flat|nested] 7+ messages in thread

* [PATCH] Retire git-parse-remote.
  2005-08-20 18:13 Updated multi-head downloads and $GIT_DIR/remotes/ support Junio C Hamano
  2005-08-20 18:22 ` [PATCH] Start adding the " Junio C Hamano
  2005-08-20 18:25 ` [PATCH] Multi-head fetch Junio C Hamano
@ 2005-08-20 18:25 ` Junio C Hamano
  2005-08-20 18:25 ` [PATCH] Infamous 'octopus merge' Junio C Hamano
                   ` (2 subsequent siblings)
  5 siblings, 0 replies; 7+ messages in thread
From: Junio C Hamano @ 2005-08-20 18:25 UTC (permalink / raw
  To: git

Update git-pull to match updated git-fetch and allow pull to
fetch from multiple remote references.  There is no support for
resolving more than two heads, which will be done with "git
octopus".

Update "git ls-remote" to use git-parse-remote-script.

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

---

 Makefile             |    2 +
 git-ls-remote-script |    4 +--
 git-parse-remote     |   79 --------------------------------------------------
 git-pull-script      |   14 ++++++---
 4 files changed, 12 insertions(+), 87 deletions(-)
 delete mode 100755 git-parse-remote

07c44b628e605c4e7fead8ff9e191711b7abe301
diff --git a/Makefile b/Makefile
--- a/Makefile
+++ b/Makefile
@@ -64,7 +64,7 @@ SCRIPTS=git git-apply-patch-script git-m
 	git-reset-script git-add-script git-checkout-script git-clone-script \
 	gitk git-cherry git-rebase-script git-relink-script git-repack-script \
 	git-format-patch-script git-sh-setup-script git-push-script \
-	git-branch-script git-parse-remote git-parse-remote-script git-verify-tag-script \
+	git-branch-script git-parse-remote-script git-verify-tag-script \
 	git-ls-remote-script git-clone-dumb-http git-rename-script \
 	git-request-pull-script git-bisect-script
 
diff --git a/git-ls-remote-script b/git-ls-remote-script
--- a/git-ls-remote-script
+++ b/git-ls-remote-script
@@ -29,8 +29,8 @@ case ",$heads,$tags," in
 ,,,) heads=heads tags=tags other=other ;;
 esac
 
-. git-parse-remote "$1"
-peek_repo="$_remote_repo"
+. git-parse-remote-script
+peek_repo="$(get_remote_url)"
 shift
 
 tmp=.ls-remote-$$
diff --git a/git-parse-remote b/git-parse-remote
deleted file mode 100755
--- a/git-parse-remote
+++ /dev/null
@@ -1,79 +0,0 @@
-: To be included in git-pull and git-fetch scripts.
-
-# A remote repository can be specified on the command line
-# in one of the following formats:
-#
-#	<repo>
-#	<repo> <head>
-#	<repo> tag <tag>
-#
-# where <repo> could be one of:
-#
-#	a URL (including absolute or local pathname)
-#	a short-hand
-#	a short-hand followed by a trailing path
-#
-# A short-hand <name> has a corresponding file $GIT_DIR/branches/<name>,
-# whose contents is a URL, possibly followed by a URL fragment #<head>
-# to name the default branch on the remote side to fetch from.
-
-_remote_repo= _remote_store= _remote_head= _remote_name=
-
-case "$1" in
-*:* | /* | ../* | ./* )
-	_remote_repo="$1"
-	;;
-* )
-	# otherwise, it is a short hand.
-	case "$1" in
-	*/*)
-		# a short-hand followed by a trailing path
-		_token=$(expr "$1" : '\([^/]*\)/')
-		_rest=$(expr "$1" : '[^/]*\(/.*\)$')
-		;;
-	*)
-		_token="$1"
-		_rest=
-		_remote_store="refs/heads/$_token"
-		;;
-	esac
-	test -f "$GIT_DIR/branches/$_token" ||
-	die "No such remote branch: $_token"
-
-	_remote_repo=$(cat "$GIT_DIR/branches/$_token")"$_rest"
-	;;
-esac
-
-case "$_remote_repo" in
-*"#"*)
-	_remote_head=`expr "$_remote_repo" : '.*#\(.*\)$'`
-	_remote_repo=`expr "$_remote_repo" : '\(.*\)#'`
-	;;
-esac
-
-_remote_name=$(echo "$_remote_repo" | sed 's|\.git/*$||')
-
-case "$2" in
-tag)
-	_remote_name="tag '$3' of $_remote_name"
-	_remote_head="refs/tags/$3"
-	_remote_store="$_remote_head"
-	;;
-?*)
-	# command line specified a head explicitly; do not
-	# store the fetched head as a branch head.
-	_remote_name="head '$2' of $_remote_name"
-	_remote_head="refs/heads/$2"
-	_remote_store=''
-	;;
-'')
-	case "$_remote_head" in
-	'')
-		_remote_head=HEAD ;;
-	*)
-		_remote_name="head '$_remote_head' of $_remote_name"
-		_remote_head="refs/heads/$_remote_head"
-		;;
-	esac
-	;;
-esac
diff --git a/git-pull-script b/git-pull-script
--- a/git-pull-script
+++ b/git-pull-script
@@ -1,12 +1,16 @@
 #!/bin/sh
 #
 . git-sh-setup-script || die "Not a git archive"
-. git-parse-remote "$@"
-merge_name="$_remote_name"
-
 git-fetch-script "$@" || exit 1
+merge_head=$(sed -e 's/	.*//' "$GIT_DIR"/FETCH_HEAD | tr '\012' ' ')
+merge_name=$(sed -e 's/^[0-9a-f]*	//' "$GIT_DIR"/FETCH_HEAD |
+	 tr '\012' ' ')
+
+case "$merge_head" in
+'' | *' '?*) die "Cannot resolve multiple heads at the same time (yet)." ;;
+esac
+
 
 git-resolve-script \
 	"$(cat "$GIT_DIR"/HEAD)" \
-	"$(cat "$GIT_DIR"/FETCH_HEAD)" \
-	"Merge $merge_name"
+	$merge_head "Merge $merge_name"

^ permalink raw reply	[flat|nested] 7+ messages in thread

* [PATCH] Infamous 'octopus merge'
  2005-08-20 18:13 Updated multi-head downloads and $GIT_DIR/remotes/ support Junio C Hamano
                   ` (2 preceding siblings ...)
  2005-08-20 18:25 ` [PATCH] Retire git-parse-remote Junio C Hamano
@ 2005-08-20 18:25 ` Junio C Hamano
  2005-08-20 18:25 ` [PATCH] Make "git pull" and "git fetch" default to origin Junio C Hamano
  2005-08-20 18:25 ` [PATCH] Use .git/remote/origin, not .git/branches/origin Junio C Hamano
  5 siblings, 0 replies; 7+ messages in thread
From: Junio C Hamano @ 2005-08-20 18:25 UTC (permalink / raw
  To: git

This script uses the list of heads and their origin multi-head "git
fetch" left in the $GIT_DIR/FETCH_HEAD file, and makes an octopus
merge on top of the current HEAD using them.

The implementation tries to be strict for the sake of safety.  It
insists that your working tree is clean (no local changes) and matches
the HEAD, and when any of the merged heads does not automerge, the
whole process is aborted and tries to rewind your working tree is to
the original state.

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

---

 Makefile           |    1 +
 git-octopus-script |  103 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 104 insertions(+), 0 deletions(-)
 create mode 100755 git-octopus-script

325918bdc88517826fb7f14fba87a34b92ea2b52
diff --git a/Makefile b/Makefile
--- a/Makefile
+++ b/Makefile
@@ -72,6 +72,7 @@ SCRIPTS += git-count-objects-script
 # SCRIPTS += git-send-email-script
 SCRIPTS += git-revert-script
 SCRIPTS += git-show-branches-script
+SCRIPTS += git-octopus-script
 
 PROG=   git-update-cache git-diff-files git-init-db git-write-tree \
 	git-read-tree git-commit-tree git-cat-file git-fsck-cache \
diff --git a/git-octopus-script b/git-octopus-script
new file mode 100755
--- /dev/null
+++ b/git-octopus-script
@@ -0,0 +1,103 @@
+#!/bin/sh
+#
+# Copyright (c) 2005 Junio C Hamano
+#
+# Resolve two or more trees recorded in $GIT_DIR/FETCH_HEAD.
+#
+. git-sh-setup-script || die "Not a git archive"
+
+usage () {
+    die "usage: git octopus"
+}
+
+# Sanity check the heads early.
+while read SHA1 REPO
+do
+	test $(git-cat-file -t $SHA1) = "commit" ||
+		die "$REPO given to octopus is not a commit"
+done <"$GIT_DIR/FETCH_HEAD"
+
+head=$(git-rev-parse --verify HEAD) || exit
+
+git-update-cache --refresh ||
+	die "Your working tree is dirty."
+test "$(git-diff-cache --cached "$head")" = "" ||
+	die "Your working tree does not match HEAD."
+
+# MRC is the current "merge reference commit"
+# MRT is the current "merge result tree"
+
+MRC=$head MSG= PARENT="-p $head"
+MRT=$(git-write-tree)
+CNT=1 ;# counting our head
+NON_FF_MERGE=0
+while read SHA1 REPO
+do
+	common=$(git-merge-base $MRC $SHA1) ||
+		die "Unable to find common commit with $SHA1 from $REPO"
+
+	if test "$common" = $SHA1
+	then
+		echo "Already up-to-date: $REPO"
+		continue
+	fi
+
+	CNT=`expr $CNT + 1`
+	PARENT="$PARENT -p $SHA1"
+	MSG="$MSG
+	$REPO"
+
+	if test "$common,$NON_FF_MERGE" = "$MRC,0"
+	then
+		# The first head being merged was a fast-forward.
+		# Advance MRC to the head being merged, and use that
+		# tree as the intermediate result of the merge.
+		# We still need to count this as part of the parent set.
+
+		echo "Fast forwarding to: $REPO"
+		git-read-tree -u -m $head $SHA1 || exit
+		MRC=$SHA1 MRT=$(git-write-tree)
+		continue
+	fi
+
+	NON_FF_MERGE=1
+
+	echo "Trying simple merge with $REPO"
+	git-read-tree -u -m $common $MRT $SHA1 || exit
+	next=$(git-write-tree 2>/dev/null)
+	if test $? -ne 0
+	then
+		echo "Simple merge did not work, trying automatic merge."
+		git-merge-cache -o git-merge-one-file-script -a || {
+		git-read-tree --reset "$head"
+		git-checkout-tree -f -q -u -a
+		die "Automatic merge failed; should not be doing Octopus"
+		}
+		next=$(git-write-tree 2>/dev/null)
+	fi
+	MRC=$common
+	MRT=$next
+done <"$GIT_DIR/FETCH_HEAD"
+
+# Just to be careful in case the user feeds nonsense to us.
+case "$CNT" in
+1)
+	echo "No changes."
+	exit 0 ;;
+2)
+	echo "Not an Octopus; making an ordinary commit."
+	MSG="Merge "`expr "$MSG" : '.	\(.*\)'` ; # remove LF and TAB
+	;;
+*)
+	# In an octopus, the original head is just one of the equals,
+	# so we should list it as such.
+	HEAD_LINK=`readlink "$GIT_DIR/HEAD"`
+	MSG="Octopus merge of the following:
+
+	$HEAD_LINK from .$MSG"
+	;;
+esac
+result_commit=$(echo "$MSG" | git-commit-tree $MRT $PARENT)
+echo "Committed merge $result_commit"
+echo $result_commit >"$GIT_DIR"/HEAD
+git-diff-tree -p $head $result_commit | git-apply --stat

^ permalink raw reply	[flat|nested] 7+ messages in thread

* [PATCH] Make "git pull" and "git fetch" default to origin
  2005-08-20 18:13 Updated multi-head downloads and $GIT_DIR/remotes/ support Junio C Hamano
                   ` (3 preceding siblings ...)
  2005-08-20 18:25 ` [PATCH] Infamous 'octopus merge' Junio C Hamano
@ 2005-08-20 18:25 ` Junio C Hamano
  2005-08-20 18:25 ` [PATCH] Use .git/remote/origin, not .git/branches/origin Junio C Hamano
  5 siblings, 0 replies; 7+ messages in thread
From: Junio C Hamano @ 2005-08-20 18:25 UTC (permalink / raw
  To: git

Amos Waterland sent in a patch for the pre-multi-head aware
version of "git pull" to do this, but the code changed quite a
bit since then.  If there is no argument given to pull from, and
if "origin" makes sense, default to fetch/pull from "origin"
instead of barfing.

[jc: besides, the patch by Amos broke the non-default case where
explicit refspecs are specified, and did not make sure we know
what "origin" means before defaulting to it.]

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

---

 git-fetch-script |    5 ++++-
 1 files changed, 4 insertions(+), 1 deletions(-)

6d8fcdbf772f4fc4ec7ae67630b52bc8a07d7b6d
diff --git a/git-fetch-script b/git-fetch-script
--- a/git-fetch-script
+++ b/git-fetch-script
@@ -8,7 +8,10 @@ _x40="$_x40$_x40$_x40$_x40$_x40$_x40$_x4
 append=
 case "$#" in
 0)
-	die "Where do you want to fetch from?" ;;
+	test -f "$GIT_DIR/branches/origin" ||
+		test -f "$GIT_DIR/remotes/origin" ||
+			die "Where do you want to fetch from?"
+	set origin ;;
 *)
 	case "$1" in
 	-a|--a|--ap|--app|--appe|--appen|--append)

^ permalink raw reply	[flat|nested] 7+ messages in thread

* [PATCH] Use .git/remote/origin, not .git/branches/origin.
  2005-08-20 18:13 Updated multi-head downloads and $GIT_DIR/remotes/ support Junio C Hamano
                   ` (4 preceding siblings ...)
  2005-08-20 18:25 ` [PATCH] Make "git pull" and "git fetch" default to origin Junio C Hamano
@ 2005-08-20 18:25 ` Junio C Hamano
  5 siblings, 0 replies; 7+ messages in thread
From: Junio C Hamano @ 2005-08-20 18:25 UTC (permalink / raw
  To: git

Now multi-head fetch is complete, let's migrate the
default configuration for new repositories created with
the "git clone" command.

The original $GIT_DIR/branches is not deprecated yet, but create
remotes directory by default from the templates as well.

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

---

 git-clone-script    |    8 +++++---
 templates/remotes-- |    1 +
 2 files changed, 6 insertions(+), 3 deletions(-)
 create mode 100644 templates/remotes--

8ad3e7efb406377f6903171638c70b7d566254c5
diff --git a/git-clone-script b/git-clone-script
--- a/git-clone-script
+++ b/git-clone-script
@@ -127,6 +127,8 @@ yes,yes)
 esac
 
 # Update origin.
-mkdir -p "$D/.git/branches/" &&
-rm -f "$D/.git/branches/origin" &&
-echo "$repo" >"$D/.git/branches/origin"
+mkdir -p "$D/.git/remotes/" &&
+rm -f "$D/.git/remotes/origin" &&
+echo >"$D/.git/remotes/origin" \
+"URL: $repo
+Pull: master:origin"
diff --git a/templates/remotes-- b/templates/remotes--
new file mode 100644
--- /dev/null
+++ b/templates/remotes--
@@ -0,0 +1 @@
+: this is just to ensure the directory exists.

^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2005-08-20 18:25 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2005-08-20 18:13 Updated multi-head downloads and $GIT_DIR/remotes/ support Junio C Hamano
2005-08-20 18:22 ` [PATCH] Start adding the " Junio C Hamano
2005-08-20 18:25 ` [PATCH] Multi-head fetch Junio C Hamano
2005-08-20 18:25 ` [PATCH] Retire git-parse-remote Junio C Hamano
2005-08-20 18:25 ` [PATCH] Infamous 'octopus merge' Junio C Hamano
2005-08-20 18:25 ` [PATCH] Make "git pull" and "git fetch" default to origin Junio C Hamano
2005-08-20 18:25 ` [PATCH] Use .git/remote/origin, not .git/branches/origin Junio C Hamano

Code repositories for project(s) associated with this public inbox

	https://80x24.org/mirrors/git.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).