* [PATCH] Infamous 'octopus merge'
@ 2005-08-19 1:05 Junio C Hamano
0 siblings, 0 replies; 8+ messages in thread
From: Junio C Hamano @ 2005-08-19 1:05 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 | 64 ++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 65 insertions(+), 0 deletions(-)
create mode 100755 git-octopus-script
bad69944391b17bf5d4060b19e24013807409b28
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,64 @@
+#!/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 MRT=$head MSG='Octopus merge of the following: ' PARENT="-p $head"
+while read SHA1 REPO
+do
+ common=$(git-merge-base $MRC $SHA1) ||
+ die "Unable to find common commit between $SHA1 and $MRC"
+
+ git-read-tree -u -m $common $MRT $SHA1 || exit
+ next=$(git-write-tree 2>/dev/null)
+ if test $? -ne 0
+ then
+ 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
+ PARENT="$PARENT -p $SHA1"
+ MRC=$common
+ MRT=$next
+ MSG="$MSG
+ $REPO"
+done <"$GIT_DIR/FETCH_HEAD"
+
+# Just to be careful in case the user feeds nonsense to us.
+if test "$MRT" = "$head"
+then
+ echo "No changes."
+ exit 0
+fi
+
+result_commit=$(echo "$MSG" | git-commit-tree $MRT $PARENT)
+echo "Committed octopus merge $result_commit"
+echo $result_commit >"$GIT_DIR"/HEAD
+git-diff-tree -p $head $result_commit | git-apply --stat
^ permalink raw reply [flat|nested] 8+ messages in thread
* 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; 8+ 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] 8+ 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; 8+ 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] 8+ 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; 8+ 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] 8+ 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; 8+ 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] 8+ 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; 8+ 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] 8+ 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; 8+ 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] 8+ 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; 8+ 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] 8+ messages in thread
end of thread, other threads:[~2005-08-20 18:25 UTC | newest]
Thread overview: 8+ 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
-- strict thread matches above, loose matches on Subject: below --
2005-08-19 1:05 [PATCH] Infamous 'octopus merge' 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).