From ccf1ee327f9a7d51704578fa41ba255abfd3a730 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Wed, 24 Aug 2005 10:40:58 -0700 Subject: Generate pack info file after repack. Pulling from a packed repository over dumb transport without the server info file fails, so run update-server-info automatically after a repack by default. This can be disabled with the '-n' flag. Signed-off-by: Junio C Hamano --- git-repack-script | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/git-repack-script b/git-repack-script index 15b7fd6a15..1c9a6315dd 100755 --- a/git-repack-script +++ b/git-repack-script @@ -1,6 +1,20 @@ #!/bin/sh +# +# Copyright (c) 2005 Linus Torvalds +# + . git-sh-setup-script || die "Not a git archive" +no_update_info= +while case "$#" in 0) break ;; esac +do + case "$1" in + -n) no_update_info=t ;; + *) break ;; + esac + shift +done + rm -f .tmp-pack-* packname=$(git-rev-list --unpacked --objects $(git-rev-parse --all) | git-pack-objects --non-empty --incremental .tmp-pack) || @@ -9,6 +23,11 @@ if [ -z "$packname" ]; then echo Nothing new to pack exit 0 fi + mkdir -p "$GIT_OBJECT_DIRECTORY/pack" && mv .tmp-pack-$packname.pack "$GIT_OBJECT_DIRECTORY/pack/pack-$packname.pack" && -mv .tmp-pack-$packname.idx "$GIT_OBJECT_DIRECTORY/pack/pack-$packname.idx" +mv .tmp-pack-$packname.idx "$GIT_OBJECT_DIRECTORY/pack/pack-$packname.idx" && +case "$no_update_info" in +t) : ;; +*) git-update-server-info ;; +esac -- cgit v1.2.3 From 4866ccf0f434db118c4dcdeeab840eb4844d50a4 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Wed, 24 Aug 2005 14:30:04 -0700 Subject: Rationalize output selection in rev-parse. Earlier rounds broke 'whatchanged -p'. In attempting to fix this, make two axis of output selection in rev-parse orthogonal: --revs-only tells it not to output things that are not revisions nor flags that rev-list would take. --no-revs tells it not to output things that are revisions or flags that rev-list would take. --flags tells it not to output parameters that do not start with a '-'. --no-flags tells it not to output parameters that starts with a '-'. So for example 'rev-parse --no-revs -p arch/i386' would yield '-p arch/i386', while 'rev-parse --no-revs --flags -p archi/i386' would give just '-p'. Also the meaning of --verify has been made stronger. It now rejects anything but a single valid rev argument. Earlier it passed some flags through without complaining. Signed-off-by: Junio C Hamano --- rev-parse.c | 121 +++++++++++++++++++++++++++--------------------------------- 1 file changed, 54 insertions(+), 67 deletions(-) diff --git a/rev-parse.c b/rev-parse.c index 9281b45d1f..6d723f902a 100644 --- a/rev-parse.c +++ b/rev-parse.c @@ -7,20 +7,21 @@ #include "commit.h" #include "refs.h" +#define DO_REVS 1 +#define DO_NOREV 2 +#define DO_FLAGS 4 +#define DO_NONFLAGS 8 +static int filter = ~0; + static char *def = NULL; -static int no_revs = 0; -static int single_rev = 0; -static int revs_only = 0; -static int do_rev_argument = 1; -static int output_revs = 0; -static int flags_only = 0; -static int no_flags = 0; -static int output_sq = 0; -static int symbolic = 0; #define NORMAL 0 #define REVERSED 1 static int show_type = NORMAL; +static int symbolic = 0; +static int output_sq = 0; + +static int revs_count = 0; /* * Some arguments are relevant "revision" arguments, @@ -30,13 +31,19 @@ static int show_type = NORMAL; static int is_rev_argument(const char *arg) { static const char *rev_args[] = { - "--max-count=", + "--bisect", + "--header", "--max-age=", - "--min-age=", + "--max-count=", "--merge-order", - "--topo-order", - "--bisect", + "--min-age=", "--no-merges", + "--objects", + "--parents", + "--pretty", + "--show-breaks", + "--topo-order", + "--unpacked", NULL }; const char **p = rev_args; @@ -47,11 +54,13 @@ static int is_rev_argument(const char *arg) if (!str) return 0; len = strlen(str); - if (!strncmp(arg, str, len)) + if (!strcmp(arg, str) || + (str[len-1] == '=' && !strncmp(arg, str, len))) return 1; } } +/* Output argument as a string, either SQ or normal */ static void show(const char *arg) { if (output_sq) { @@ -70,11 +79,13 @@ static void show(const char *arg) puts(arg); } +/* Output a revision, only if filter allows it */ static void show_rev(int type, const unsigned char *sha1, const char *name) { - if (no_revs) + if (!(filter & DO_REVS)) return; - output_revs++; + def = NULL; + revs_count++; if (type != show_type) putchar('^'); @@ -84,29 +95,12 @@ static void show_rev(int type, const unsigned char *sha1, const char *name) show(sha1_to_hex(sha1)); } -static void show_rev_arg(char *rev) +/* Output a flag, only if filter allows it. */ +static void show_flag(char *arg) { - if (no_revs) + if (!(filter & DO_FLAGS)) return; - show(rev); -} - -static void show_norev(char *norev) -{ - if (flags_only) - return; - if (revs_only) - return; - show(norev); -} - -static void show_arg(char *arg) -{ - if (no_flags) - return; - if (do_rev_argument && is_rev_argument(arg)) - show_rev_arg(arg); - else + if (filter & (is_rev_argument(arg) ? DO_REVS : DO_NOREV)) show(arg); } @@ -122,7 +116,6 @@ static void show_default(void) show_rev(NORMAL, sha1, s); return; } - show_norev(s); } } @@ -134,7 +127,7 @@ static int show_reference(const char *refname, const unsigned char *sha1) int main(int argc, char **argv) { - int i, as_is = 0; + int i, as_is = 0, verify = 0; unsigned char sha1[20]; const char *prefix = setup_git_directory(); @@ -143,15 +136,13 @@ int main(int argc, char **argv) char *dotdot; if (as_is) { - show_norev(arg); + show(arg); continue; } if (*arg == '-') { if (!strcmp(arg, "--")) { - show_default(); - if (revs_only || flags_only) - break; as_is = 1; + continue; } if (!strcmp(arg, "--default")) { def = argv[i+1]; @@ -159,25 +150,24 @@ int main(int argc, char **argv) continue; } if (!strcmp(arg, "--revs-only")) { - revs_only = 1; + filter &= ~DO_NOREV; continue; } if (!strcmp(arg, "--no-revs")) { - no_revs = 1; + filter &= ~DO_REVS; continue; } if (!strcmp(arg, "--flags")) { - flags_only = 1; + filter &= ~DO_NONFLAGS; continue; } if (!strcmp(arg, "--no-flags")) { - no_flags = 1; + filter &= ~DO_FLAGS; continue; } if (!strcmp(arg, "--verify")) { - revs_only = 1; - do_rev_argument = 0; - single_rev = 1; + filter &= ~(DO_FLAGS|DO_NOREV); + verify = 1; continue; } if (!strcmp(arg, "--sq")) { @@ -197,12 +187,17 @@ int main(int argc, char **argv) continue; } if (!strcmp(arg, "--show-prefix")) { - puts(prefix); + if (prefix) + puts(prefix); continue; } - show_arg(arg); + if (verify) + die("Needed a single revision"); + show_flag(arg); continue; } + + /* Not a flag argument */ dotdot = strstr(arg, ".."); if (dotdot) { unsigned char end[20]; @@ -212,9 +207,6 @@ int main(int argc, char **argv) if (!*n) n = "HEAD"; if (!get_sha1(n, end)) { - if (no_revs) - continue; - def = NULL; show_rev(NORMAL, end, n); show_rev(REVERSED, sha1, arg); continue; @@ -223,26 +215,21 @@ int main(int argc, char **argv) *dotdot = '.'; } if (!get_sha1(arg, sha1)) { - if (no_revs) - continue; - def = NULL; show_rev(NORMAL, sha1, arg); continue; } if (*arg == '^' && !get_sha1(arg+1, sha1)) { - if (no_revs) - continue; - def = NULL; show_rev(REVERSED, sha1, arg+1); continue; } - show_default(); - show_norev(arg); + if (verify) + die("Needed a single revision"); + if ((filter & (DO_NONFLAGS|DO_NOREV)) == + (DO_NONFLAGS|DO_NOREV)) + show(arg); } show_default(); - if (single_rev && output_revs != 1) { - fprintf(stderr, "Needed a single revision\n"); - exit(1); - } + if (verify && revs_count != 1) + die("Needed a single revision"); return 0; } -- cgit v1.2.3 From ff84d327dfb8a9aa0634b0aaaca1c018cdc5117a Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Wed, 24 Aug 2005 14:31:36 -0700 Subject: Audit rev-parse users again. Some callers to rev-parse were using the output selection flags inconsistently. Signed-off-by: Junio C Hamano --- git-bisect-script | 4 ++-- git-branch-script | 2 +- git-log-script | 2 +- git-request-pull-script | 4 ++-- git-revert-script | 2 +- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/git-bisect-script b/git-bisect-script index 29b25f4a4c..0c5c10750e 100755 --- a/git-bisect-script +++ b/git-bisect-script @@ -58,7 +58,7 @@ bisect_start() { bisect_bad() { bisect_autostart case "$#" in 0 | 1) ;; *) usage ;; esac - rev=$(git-rev-parse --revs-only --verify --default HEAD "$@") || exit + rev=$(git-rev-parse --verify --default HEAD "$@") || exit echo "$rev" > "$GIT_DIR/refs/bisect/bad" bisect_auto_next } @@ -67,7 +67,7 @@ bisect_good() { bisect_autostart case "$#" in 0) revs=$(git-rev-parse --verify HEAD) || exit ;; - *) revs=$(git-rev-parse --revs-only "$@") || exit ;; + *) revs=$(git-rev-parse --revs-only --no-flags "$@") || exit ;; esac for rev in $revs do diff --git a/git-branch-script b/git-branch-script index a6dfeaf55f..0ecbd239ac 100755 --- a/git-branch-script +++ b/git-branch-script @@ -25,7 +25,7 @@ case "$#" in head="$2^0" ;; esac branchname="$1" -rev=$(git-rev-parse --revs-only --verify "$head") || exit +rev=$(git-rev-parse --verify "$head") || exit [ -e "$GIT_DIR/refs/heads/$branchname" ] && die "$branchname already exists" diff --git a/git-log-script b/git-log-script index 9260f92055..5716b29941 100755 --- a/git-log-script +++ b/git-log-script @@ -1,4 +1,4 @@ #!/bin/sh -revs=$(git-rev-parse --revs-only --default HEAD "$@") || exit +revs=$(git-rev-parse --revs-only --no-flags --default HEAD "$@") || exit [ "$revs" ] || die "No HEAD ref" git-rev-list --pretty $(git-rev-parse --default HEAD "$@") | LESS=-S ${PAGER:-less} diff --git a/git-request-pull-script b/git-request-pull-script index 9190815229..ae6cd272ba 100755 --- a/git-request-pull-script +++ b/git-request-pull-script @@ -19,8 +19,8 @@ head=${3-HEAD} [ "$revision" ] || usage [ "$url" ] || usage -baserev=`git-rev-parse --verify $revision^0` && -headrev=`git-rev-parse --verify $head^0` || exit +baserev=`git-rev-parse --verify "$revision"^0` && +headrev=`git-rev-parse --verify "$head"^0` || exit echo "The following changes since commit $baserev:" git log --max-count=1 --pretty=short "$baserev" | diff --git a/git-revert-script b/git-revert-script index dc2dea4898..22f2082fb1 100755 --- a/git-revert-script +++ b/git-revert-script @@ -10,7 +10,7 @@ case "$status" in die "Your working tree is dirty; cannot revert a previous patch." ;; esac -rev=$(git-rev-parse --no-flags --verify --revs-only "$@") && +rev=$(git-rev-parse --verify "$@") && commit=$(git-rev-parse --verify "$rev^0") || exit if git-diff-tree -R -M -p $commit | git-apply --index && msg=$(git-rev-list --pretty=oneline --max-count=1 $commit) -- cgit v1.2.3 From d998a0895fc20c03007d8b2a74b78b37e1cdfaba Mon Sep 17 00:00:00 2001 From: Pavel Roskin Date: Wed, 24 Aug 2005 17:58:42 -0400 Subject: [PATCH] Fix "prefix" mixup in git-rev-list Recent changes in git have broken cg-log. git-rev-list no longer prints "commit" in front of commit hashes. It turn out a local "prefix" variable in main() shadows a file-scoped "prefix" variable. The patch removed the local "prefix" variable since its value is never used (in the intended way, that is). The call to setup_git_directory() is kept since it has useful side effects. The file-scoped "prefix" variable is renamed to "commit_prefix" just in case someone reintroduces "prefix" to hold the return value of setup_git_directory(). Signed-off-by: Pavel Roskin Signed-off-by: Junio C Hamano --- rev-list.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/rev-list.c b/rev-list.c index 3643adb631..2d97cdb64b 100644 --- a/rev-list.c +++ b/rev-list.c @@ -33,7 +33,7 @@ static int blob_objects = 0; static int verbose_header = 0; static int show_parents = 0; static int hdr_termination = 0; -static const char *prefix = ""; +static const char *commit_prefix = ""; static unsigned long max_age = -1; static unsigned long min_age = -1; static int max_count = -1; @@ -48,14 +48,14 @@ static void show_commit(struct commit *commit) { commit->object.flags |= SHOWN; if (show_breaks) { - prefix = "| "; + commit_prefix = "| "; if (commit->object.flags & DISCONTINUITY) { - prefix = "^ "; + commit_prefix = "^ "; } else if (commit->object.flags & BOUNDARY) { - prefix = "= "; + commit_prefix = "= "; } } - printf("%s%s", prefix, sha1_to_hex(commit->object.sha1)); + printf("%s%s", commit_prefix, sha1_to_hex(commit->object.sha1)); if (show_parents) { struct commit_list *parents = commit->parents; while (parents) { @@ -481,9 +481,9 @@ static void handle_one_commit(struct commit *com, struct commit_list **lst) int main(int argc, char **argv) { struct commit_list *list = NULL; - const char *prefix = setup_git_directory(); int i, limited = 0; + setup_git_directory(); for (i = 1 ; i < argc; i++) { int flags; char *arg = argv[i]; @@ -511,9 +511,9 @@ int main(int argc, char **argv) verbose_header = 1; hdr_termination = '\n'; if (commit_format == CMIT_FMT_ONELINE) - prefix = ""; + commit_prefix = ""; else - prefix = "commit "; + commit_prefix = "commit "; continue; } if (!strncmp(arg, "--no-merges", 11)) { -- cgit v1.2.3 From ac4b0cff00b7629657e61a1d6e1f1a1250d03198 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Sat, 20 Aug 2005 02:52:24 -0700 Subject: [PATCH] Start adding the $GIT_DIR/remotes/ support. All the necessary parsing code is in git-parse-remote-script; update git-push-script to use it. Signed-off-by: Junio C Hamano --- 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 diff --git a/Makefile b/Makefile index ac4f2110dc..752affe407 100644 --- a/Makefile +++ b/Makefile @@ -64,7 +64,7 @@ SCRIPTS=git git-apply-patch-script git-merge-one-file-script git-prune-script \ 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 index 0000000000..2da7ae8470 --- /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 index 70fa9684a5..5fa5af2af8 100755 --- 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://* ) -- cgit v1.2.3 From 853a3697dc2bc609650c38ed03a1f8fa9f145f97 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Sat, 20 Aug 2005 02:54:34 -0700 Subject: [PATCH] Multi-head fetch. Traditionally, fetch takes these forms: $ git fetch $ git fetch $ git fetch tag This patch updates it to take $ git fetch ... where: - A of form ":" is to fetch the objects needed for the remote ref that matches , and if is not empty, store it as a local . - "tag" followed by is just an old way of saying "refs/tags/:refs/tags/"; 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 without colon is a shorthand for ":" That is, "fetch that ref but do not store anywhere". - when there is no specified - if is the name of a file under $GIT_DIR/remotes/ (i.e. a new-style shorthand), then it is the same as giving the s listed on Pull: line in that file. - if 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 ":refs/heads/" on the command line, where is the remote branch name (defaults to HEAD, but can be overridden by .git/branches/ file having the URL fragment notation). That is, "fetch that branch head and store it in refs/heads/". - otherwise, it is the same as giving a single 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 --- git-fetch-script | 189 ++++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 147 insertions(+), 42 deletions(-) diff --git a/git-fetch-script b/git-fetch-script index ea097144f7..9b05e41176 100755 --- 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 + esac +} + +for ref in $(get_remote_refs_for_fetch "$@") +do + refs="$refs $ref" -git-rev-parse --verify "$head" > /dev/null || exit 1 + # These are relative path from $GIT_DIR, typically starting at refs/ + # but may be HEAD + remote_name=$(expr "$ref" : '\([^:]*\):') + local_name=$(expr "$ref" : '[^:]*:\(.*\)') -case "$merge_store" in -'') + 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 ;; -*) - echo "$head" > "$GIT_DIR/$merge_store" -esac && + 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" -# 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. +done + +case "$remote" in +http://* | https://* | rsync://* ) + ;; # we are already done. +*) + 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 -git-rev-parse "$head^0" >"$GIT_DIR/FETCH_HEAD" + local_name=$(expr "$found" : '[^:]*:\(.*\)') + append_fetch_head "$sha1" "$remote" "$remote_name" "$remote_nick" "$local_name" + done + ;; +esac -- cgit v1.2.3 From e0bfc81e05e57679916ab070c8fb2525f24771d4 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Sat, 20 Aug 2005 02:57:26 -0700 Subject: [PATCH] Retire git-parse-remote. 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 --- 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 diff --git a/Makefile b/Makefile index 752affe407..267de67fd7 100644 --- a/Makefile +++ b/Makefile @@ -64,7 +64,7 @@ SCRIPTS=git git-apply-patch-script git-merge-one-file-script git-prune-script \ 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 index 75f6027866..061a23135c 100755 --- 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 index 53c5842ef3..0000000000 --- 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: -# -# -# -# tag -# -# where 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 has a corresponding file $GIT_DIR/branches/, -# whose contents is a URL, possibly followed by a URL fragment # -# 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 index fc463260bd..8608fcdebc 100755 --- 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" -- cgit v1.2.3 From d9f3be7e2e4c9b402bbe6ee6e2b39b2ee89132cf Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Sat, 20 Aug 2005 02:58:42 -0700 Subject: [PATCH] Infamous 'octopus merge' 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 --- Makefile | 1 + git-octopus-script | 103 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 104 insertions(+) create mode 100755 git-octopus-script diff --git a/Makefile b/Makefile index 267de67fd7..4d1c11166e 100644 --- a/Makefile +++ b/Makefile @@ -71,6 +71,7 @@ SCRIPTS=git git-apply-patch-script git-merge-one-file-script git-prune-script \ SCRIPTS += git-count-objects-script # SCRIPTS += git-send-email-script SCRIPTS += git-revert-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 index 0000000000..80edfd42e4 --- /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-cache -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 -- cgit v1.2.3 From 92c533ef0ea2cb43f0d7d493f006f5b4dfa7cda1 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Sat, 20 Aug 2005 03:00:03 -0700 Subject: [PATCH] Make "git pull" and "git fetch" default to origin 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 --- git-fetch-script | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/git-fetch-script b/git-fetch-script index 9b05e41176..a70909e4ff 100755 --- a/git-fetch-script +++ b/git-fetch-script @@ -8,7 +8,10 @@ _x40="$_x40$_x40$_x40$_x40$_x40$_x40$_x40$_x40" 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) -- cgit v1.2.3 From 6687f8fea22e1e43ab163a8fe180155a0a0a956a Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Sat, 20 Aug 2005 03:05:42 -0700 Subject: [PATCH] Use .git/remote/origin, not .git/branches/origin. 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 --- git-clone-script | 8 +++++--- templates/remotes-- | 1 + 2 files changed, 6 insertions(+), 3 deletions(-) create mode 100644 templates/remotes-- diff --git a/git-clone-script b/git-clone-script index 99c2459631..f988b8c9c7 100755 --- 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 index 0000000000..fae88709a6 --- /dev/null +++ b/templates/remotes-- @@ -0,0 +1 @@ +: this is just to ensure the directory exists. -- cgit v1.2.3 From ae2da40690a3f3f101de5780a7799781b09e2e05 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Mon, 22 Aug 2005 21:28:33 -0700 Subject: [PATCH] "git fetch --force". Just like "git push" can forcibly update a ref to a value that is not a fast-forward, teach "git fetch" to do so as well. Signed-off-by: Junio C Hamano --- git-fetch-script | 45 +++++++++++++++++++++++++++++++++++++-------- 1 file changed, 37 insertions(+), 8 deletions(-) diff --git a/git-fetch-script b/git-fetch-script index a70909e4ff..dc7f4d6e44 100755 --- a/git-fetch-script +++ b/git-fetch-script @@ -6,19 +6,32 @@ _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= +force= +while case "$#" in 0) break ;; esac +do + case "$1" in + -a|--a|--ap|--app|--appe|--appen|--append) + append=t + shift + ;; + -f|--f|--fo|--for|--forc|--force) + force=t + shift + ;; + *) + break + ;; + esac +done + case "$#" in 0) 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) - append=t - shift ;; - esac esac + remote_nick="$1" remote=$(get_remote_url "$@") refs= @@ -60,7 +73,16 @@ fast_forward_local () { refs/tags/*) # Tags need not be pointing at commits so there # is no way to guarantee "fast-forward" anyway. + if test -f "$GIT_DIR/$1" + then + echo >&2 "* $1: updating with $4" + echo >&2 " from $3." + else + echo >&2 "* $1: storing $4" + echo >&2 " from $3." + fi echo "$2" >"$GIT_DIR/$1" ;; + refs/heads/*) # NEEDSWORK: use the same cmpxchg protocol here. echo "$2" >"$GIT_DIR/$1.lock" @@ -81,9 +103,16 @@ fast_forward_local () { 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'" + case "$force" in + t) + echo >&2 " from $3; forcing update." + ;; + *) + mv "$GIT_DIR/$1.lock" "$GIT_DIR/$1.remote" + echo >&2 " from $3; leaving it in '$1.remote'" + ;; + esac } else echo >&2 "* $1: storing $4" -- cgit v1.2.3 From 521003ff52d1cf742350e1342bc2dd4ab1b51e6b Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Mon, 22 Aug 2005 21:57:59 -0700 Subject: [PATCH] Use git-octopus when pulling more than one heads. With this, you can finally say "git pull jgarzik sil24 pdc2027x". Signed-off-by: Junio C Hamano --- git-pull-script | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/git-pull-script b/git-pull-script index 8608fcdebc..7016fbf943 100755 --- a/git-pull-script +++ b/git-pull-script @@ -1,5 +1,9 @@ #!/bin/sh # +# Copyright (c) 2005 Junio C Hamano +# +# Fetch one or more remote refs and merge it/them into the current HEAD. + . git-sh-setup-script || die "Not a git archive" git-fetch-script "$@" || exit 1 merge_head=$(sed -e 's/ .*//' "$GIT_DIR"/FETCH_HEAD | tr '\012' ' ') @@ -7,10 +11,16 @@ 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)." ;; +'') + echo >&2 "No changes." + exit 0 + ;; +*' '?*) + echo >&2 "Pulling more than one heads; making an Octopus." + exec git-octopus-script + ;; esac - git-resolve-script \ "$(cat "$GIT_DIR"/HEAD)" \ $merge_head "Merge $merge_name" -- cgit v1.2.3 From efe9bf0f3b34d12b3b76f8277550f91700609b25 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Mon, 22 Aug 2005 22:52:43 -0700 Subject: [PATCH] Allow "+remote:local" refspec to cause --force when fetching. With this we could say: Pull: master:ko-master +pu:ko-pu to mean "fast forward ko-master with master, overwrite ko-pu with pu", and the latter one does not require the remote "pu" to be descendant of local "ko-pu". Signed-off-by: Junio C Hamano --- git-fetch-script | 18 +++++++++++++++--- git-parse-remote-script | 15 +++++++++++---- 2 files changed, 26 insertions(+), 7 deletions(-) diff --git a/git-fetch-script b/git-fetch-script index dc7f4d6e44..d55cc85620 100755 --- a/git-fetch-script +++ b/git-fetch-script @@ -104,8 +104,8 @@ fast_forward_local () { ;; esac || { echo >&2 "* $1: does not fast forward to $4" - case "$force" in - t) + case "$force,$single_force" in + t,* | *,t) echo >&2 " from $3; forcing update." ;; *) @@ -130,6 +130,13 @@ do # These are relative path from $GIT_DIR, typically starting at refs/ # but may be HEAD + if expr "$ref" : '\+' >/dev/null + then + single_force=t + ref=$(expr "$ref" : '\+\(.*\)') + else + single_force= + fi remote_name=$(expr "$ref" : '\([^:]*\):') local_name=$(expr "$ref" : '[^:]*:\(.*\)') @@ -175,9 +182,14 @@ http://* | https://* | rsync://* ) while read sha1 remote_name do found= + single_force= for ref in $refs do case "$ref" in + +$remote_name:*) + single_force=t + found="$ref" + break ;; $remote_name:*) found="$ref" break ;; @@ -185,7 +197,7 @@ http://* | https://* | rsync://* ) done local_name=$(expr "$found" : '[^:]*:\(.*\)') - append_fetch_head "$sha1" "$remote" "$remote_name" "$remote_nick" "$local_name" + append_fetch_head "$sha1" "$remote" "$remote_name" "$remote_nick" "$local_name" done ;; esac diff --git a/git-parse-remote-script b/git-parse-remote-script index 2da7ae8470..cf37884256 100755 --- a/git-parse-remote-script +++ b/git-parse-remote-script @@ -5,7 +5,7 @@ get_data_source () { case "$1" in */*) - # Not so fast. This could be the partial URL shorthand... + # Not so fast. This could be the partial URL shorthand... token=$(expr "$1" : '\([^/]*\)/') remainder=$(expr "$1" : '[^/]*/\(.*\)') if test -f "$GIT_DIR/branches/$token" @@ -69,6 +69,13 @@ get_remote_default_refs_for_push () { canon_refs_list_for_fetch () { for ref do + force= + case "$ref" in + +*) + ref=$(expr "$ref" : '\+\(.*\)') + force=+ + ;; + esac expr "$ref" : '.*:' >/dev/null || ref="${ref}:" remote=$(expr "$ref" : '\([^:]*\):') local=$(expr "$ref" : '[^:]*:\(.*\)') @@ -80,7 +87,7 @@ canon_refs_list_for_fetch () { '') local= ;; *) local="refs/heads/$local" ;; esac - echo "${remote}:${local}" + echo "${force}${remote}:${local}" done } @@ -132,12 +139,12 @@ get_remote_refs_for_fetch () { else case "$ref" in tag) - tag_just_seen=yes + tag_just_seen=yes continue ;; esac fi - canon_refs_list_for_fetch "$ref" + canon_refs_list_for_fetch "$ref" done ;; esac -- cgit v1.2.3 From ff27adf3dae36695f1af1b6f0e01ec6738ce0249 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Wed, 24 Aug 2005 00:40:14 -0700 Subject: Support +: format in push as well. Signed-off-by: Junio C Hamano --- cache.h | 1 + connect.c | 17 +++++++++++++++-- send-pack.c | 12 ++++++++---- 3 files changed, 24 insertions(+), 6 deletions(-) diff --git a/cache.h b/cache.h index ba5c4ab7ee..1478631b40 100644 --- a/cache.h +++ b/cache.h @@ -309,6 +309,7 @@ struct ref { struct ref *next; unsigned char old_sha1[20]; unsigned char new_sha1[20]; + unsigned char force; struct ref *peer_ref; /* when renaming */ char name[0]; }; diff --git a/connect.c b/connect.c index a6657b1384..7cd587357e 100644 --- a/connect.c +++ b/connect.c @@ -82,15 +82,26 @@ int path_match(const char *path, int nr, char **match) struct refspec { char *src; char *dst; + char force; }; +/* + * A:B means fast forward remote B with local A. + * +A:B means overwrite remote B with local A. + * +A is a shorthand for +A:A. + * A is a shorthand for A:A. + */ static struct refspec *parse_ref_spec(int nr_refspec, char **refspec) { int i; - struct refspec *rs = xmalloc(sizeof(*rs) * (nr_refspec + 1)); + struct refspec *rs = xcalloc(sizeof(*rs), (nr_refspec + 1)); for (i = 0; i < nr_refspec; i++) { char *sp, *dp, *ep; sp = refspec[i]; + if (*sp == '+') { + rs[i].force = 1; + sp++; + } ep = strchr(sp, ':'); if (ep) { dp = ep + 1; @@ -216,8 +227,10 @@ static int match_explicit_refs(struct ref *src, struct ref *dst, error("dst ref %s receives from more than one src.", matched_dst->name); } - else + else { matched_dst->peer_ref = matched_src; + matched_dst->force = rs[i].force; + } } return -errs; } diff --git a/send-pack.c b/send-pack.c index 0ab135c988..55d8ff7e10 100644 --- a/send-pack.c +++ b/send-pack.c @@ -206,7 +206,8 @@ static int send_pack(int in, int out, int nr_refspec, char **refspec) /* This part determines what can overwrite what. * The rules are: * - * (0) you can always use --force. + * (0) you can always use --force or +A:B notation to + * selectively force individual ref pairs. * * (1) if the old thing does not exist, it is OK. * @@ -218,16 +219,19 @@ static int send_pack(int in, int out, int nr_refspec, char **refspec) * descendant of old, it is OK. */ - if (!force_update && !is_zero_sha1(ref->old_sha1)) { + if (!force_update && + !is_zero_sha1(ref->old_sha1) && + !ref->force) { if (!has_sha1_file(ref->old_sha1)) { error("remote '%s' object %s does not " "exist on local", ref->name, sha1_to_hex(ref->old_sha1)); continue; } + /* We assume that local is fsck-clean. Otherwise - * you _could_ have a old tag which points at - * something you do not have which may or may not + * you _could_ have an old tag which points at + * something you do not have, which may or may not * be a commit. */ if (!ref_newer(ref->peer_ref->new_sha1, -- cgit v1.2.3 From ab9b31386b494b6c16d651d1560f3ba11c3a1964 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Wed, 24 Aug 2005 16:23:08 -0700 Subject: Documentation: multi-head fetch. Add documentation related to multi-head work, including $GIT_DIR/remotes/ changes. Signed-off-by: Junio C Hamano --- Documentation/git-fetch-script.txt | 23 ++++------- Documentation/git-octopus-script.txt | 39 ++++++++++++++++++ Documentation/git-pull-script.txt | 9 ++-- Documentation/git-push-script.txt | 14 +++---- Documentation/git-resolve-script.txt | 14 +++++-- Documentation/git-send-pack.txt | 37 +++++++++++++---- Documentation/git.txt | 17 ++++---- Documentation/pull-fetch-param.txt | 80 ++++++++++++++++++++++++++++-------- 8 files changed, 170 insertions(+), 63 deletions(-) create mode 100644 Documentation/git-octopus-script.txt diff --git a/Documentation/git-fetch-script.txt b/Documentation/git-fetch-script.txt index db3086c732..d15222b561 100644 --- a/Documentation/git-fetch-script.txt +++ b/Documentation/git-fetch-script.txt @@ -1,6 +1,6 @@ git-fetch-script(1) =================== -v0.99.4, Aug 2005 +v0.99.5, Aug 2005 NAME ---- @@ -9,24 +9,17 @@ git-fetch-script - Download objects and a head from another repository. SYNOPSIS -------- -'git-fetch-script' [ | tag ] +'git-fetch-script' ... DESCRIPTION ----------- -Fetches a named head or a tag from another repository, along -with the objects necessary to complete that head or tag. The -head to pull defaults to HEAD if unspecified. The head or tag -fetched from the remote repository is stored in -$GIT_DIR/FETCH_HEAD. - -When a is specified, the fetched from the remote is -also copied to the local $GIT_DIR/tags/ file. When no - nor is specified, and was specified -with the short-hand notation (i.e. naming a file under the -$GIT_DIR/branches directory), the head fetched from the remote -repository is also copied to the local $GIT_DIR/heads/ -file. +Fetches named heads or tags from another repository, along with +the objects necessary to complete them. + +The ref names and their object names of fetched refs are stored +in $GIT_DIR/FETCH_HEAD. This information is left for a later merge +operation done by "git resolve" or "git octopus". OPTIONS diff --git a/Documentation/git-octopus-script.txt b/Documentation/git-octopus-script.txt new file mode 100644 index 0000000000..f7a073d4f9 --- /dev/null +++ b/Documentation/git-octopus-script.txt @@ -0,0 +1,39 @@ +git-octopus-script(1) +===================== +v0.99.5, Aug 2005 + +NAME +---- +git-octopus-script - Merge more than two commits. + + +SYNOPSIS +-------- +'git-octopus' + +DESCRIPTION +----------- +After running 'git fetch', $GIT_DIR/FETCH_HEAD contains the +following information, one line per remote ref: + +------------------------------------------------ + from +------------------------------------------------ + +Using this information, create and commit an Octopus merge on +top of the current HEAD. + + +Author +------ +Written by Junio C Hamano + + +Documentation +-------------- +Documentation by Junio C Hamano and the git-list . + +GIT +--- +Part of the link:git.html[git] suite + diff --git a/Documentation/git-pull-script.txt b/Documentation/git-pull-script.txt index ad9d3ab315..8111813b85 100644 --- a/Documentation/git-pull-script.txt +++ b/Documentation/git-pull-script.txt @@ -9,13 +9,16 @@ git-pull-script - Pull and merge from another repository. SYNOPSIS -------- -'git-pull-script' [ | tag ] +'git-pull-script' ... DESCRIPTION ----------- -Runs 'git-fetch-script' with the given parameters, then -'git-resolve-script' to merge the local HEAD and FETCH_HEAD. +Runs 'git-fetch-script' with the given parameters. + +When only one ref is downloaded, runs 'git resolve' to merge it +into the local HEAD. Otherwise uses 'git octopus' to merge them +into the local HEAD. OPTIONS diff --git a/Documentation/git-push-script.txt b/Documentation/git-push-script.txt index 3c1208d5a2..556682f991 100644 --- a/Documentation/git-push-script.txt +++ b/Documentation/git-push-script.txt @@ -3,25 +3,23 @@ git-push-script(1) NAME ---- -git-push-script - Some git command not yet documented. +git-push-script - Update remote refs along with associated objects. SYNOPSIS -------- -'git-push-script' [ --option ] ... +'git-push-script' [--all] [--force] ... DESCRIPTION ----------- -Does something not yet documented. + +Updates remote refs using local refs, while sending objects +necessary to complete the given refs. OPTIONS ------- ---option:: - Some option not yet documented. - -...:: - Some argument not yet documented. +include::pull-fetch-param.txt[] Author diff --git a/Documentation/git-resolve-script.txt b/Documentation/git-resolve-script.txt index 99c399a073..77076aa90d 100644 --- a/Documentation/git-resolve-script.txt +++ b/Documentation/git-resolve-script.txt @@ -1,19 +1,25 @@ git-resolve-script(1) ===================== -v0.99.4, Aug 2005 +v0.99.5, Aug 2005 NAME ---- -git-resolve-script - Script used to merge two trees +git-resolve-script - Merge two commits SYNOPSIS -------- -'git-resolve-script' +'git resolve' DESCRIPTION ----------- -This script is used by Linus to merge two trees. +Given two commits and a merge message, merge the commit +into commit, with the commit log message . + +When is a descendant of , or is an +ancestor of , no new commit is created and the +is ignored. The former is informally called "already up to +date", and the latter is often called "fast forward". Author diff --git a/Documentation/git-send-pack.txt b/Documentation/git-send-pack.txt index 6192c5dc41..5ed25f54d1 100644 --- a/Documentation/git-send-pack.txt +++ b/Documentation/git-send-pack.txt @@ -9,12 +9,12 @@ git-send-pack - Push missing objects packed. SYNOPSIS -------- -'git-send-pack' [--all] [--exec=] [:] [...] +'git-send-pack' [--all] [--force] [--exec=] [:] [...] DESCRIPTION ----------- Invokes 'git-receive-pack' on a possibly remote repository, and -updates it from the current repository, sending named heads. +updates it from the current repository, sending named refs. OPTIONS @@ -29,6 +29,13 @@ OPTIONS Instead of explicitly specifying which refs to update, update all refs that locally exist. +--force:: + Usually, the command refuses to update a remote ref that + is not an ancestor of the local ref used to overwrite it. + This flag disables the check. What this means is that + the remote repository can lose commits; use it with + care. + :: A remote host to house the repository. When this part is specified, 'git-receive-pack' is invoked via @@ -37,7 +44,7 @@ OPTIONS :: The repository to update. -...: +...: The remote refs to update. @@ -48,24 +55,25 @@ There are three ways to specify which refs to update on the remote end. With '--all' flag, all refs that exist locally are transfered to -the remote side. You cannot specify any '' if you use +the remote side. You cannot specify any '' if you use this flag. -Without '--all' and without any '', the refs that exist +Without '--all' and without any '', the refs that exist both on the local side and on the remote side are updated. -When ''s are specified explicitly, it can be either a +When ''s are specified explicitly, it can be either a single pattern, or a pair of such pattern separated by a colon ':' (this means that a ref name cannot have a colon in it). A single pattern '' is just a shorthand for ':'. + Each pattern pair consists of the source side (before the colon) -and the destination side (after the colon). The ref that is +and the destination side (after the colon). The ref to be pushed is determined by finding a match that matches the source side, and where it is pushed is determined by using the destination side. - - It is an error if does not match exactly one of local - refs. + - It is an error if does not match exactly one of the + local refs. - It is an error if matches more than one remote refs. @@ -78,6 +86,17 @@ destination side. exist in the set of remote refs; the ref matched locally is used as the name of the destination. +Without '--force', the ref is stored at the remote only if + does not exist, or is a proper subset (i.e. an +ancestor) of . This check, known as "fast forward check", +is performed in order to avoid accidentally overwriting the +remote ref and lose other peoples' commits from there. + +With '--force', the fast forward check is disabled for all refs. + +Optionally, a parameter can be prefixed with a plus '+' sign +to disable the fast-forward check only on that ref. + Author ------ diff --git a/Documentation/git.txt b/Documentation/git.txt index d133250635..664b88a917 100644 --- a/Documentation/git.txt +++ b/Documentation/git.txt @@ -208,7 +208,16 @@ link:git-fetch-script.html[git-fetch-script]:: link:git-pull-script.html[git-pull-script]:: Fetch from and merge with a remote repository. -ulink:git-commit-script.html[git-commit-script]:: +link:git-resolve-script.html[git-resolve-script]:: + Merge two commits. + +link:git-octopus-script.html[git-octopus-script]:: + Merge more than two commits. + +link:git-push-script.html[git-push-script]:: + Update remote refs along with associated objects. + +link:git-commit-script.html[git-commit-script]:: Record changes to the repository. link:git-show-branch.html[git-show-branch]:: @@ -240,9 +249,6 @@ link:git-merge-one-file-script.html[git-merge-one-file-script]:: link:git-prune-script.html[git-prune-script]:: Prunes all unreachable objects from the object database -link:git-resolve-script.html[git-resolve-script]:: - Script used to merge two trees - link:git-tag-script.html[git-tag-script]:: An example script to create a tag object signed with GPG @@ -316,9 +322,6 @@ link:git-get-tar-commit-id.html[git-get-tar-commit-id]:: link:git-patch-id.html[git-patch-id]:: git-patch-id. -link:git-push-script.html[git-push-script]:: - git-push-script. - link:git-rebase-script.html[git-rebase-script]:: git-rebase-script. diff --git a/Documentation/pull-fetch-param.txt b/Documentation/pull-fetch-param.txt index 7ae4ba0bd8..ea0ad2c48f 100644 --- a/Documentation/pull-fetch-param.txt +++ b/Documentation/pull-fetch-param.txt @@ -16,21 +16,67 @@ Local directory /path/to/repo.git/ - In addition to that, as a short-hand, the name of a file - in $GIT_DIR/branches directory can be specified; the - named file should contain a single line, a URL in one of - the above formats, optionally followed by a hash '#' and - the name of remote head. - -:: - The remote head name to fetch from. That is, make the - objects reachable from the commit recorded in - $GIT_DIR/refs/heads/ in the remote repository - available locally. - -tag :: - The remote head tag to fetch from. That is, make the - objects reachable from the commit recorded in - $GIT_DIR/refs/tags/ in the remote repository - available locally. + In addition to the above, as a short-hand, the name of a + file in $GIT_DIR/remotes directory can be given; the + named file should be in the following format: + URL: one of the above URL format + Push: ... + Pull: ... + + When such a short-hand is specified in place of + without parameters on the command + line, ... specified on Push lines or Pull lines + are used for "git push" and "git fetch/pull", + respectively. + + The name of a file in $GIT_DIR/branches directory can be + specified as an older notation short-hand; the named + file should contain a single line, a URL in one of the + above formats, optionally followed by a hash '#' and the + name of remote head (URL fragment notation). + $GIT_DIR/branches/ file that stores a + without the fragment is equivalent to have this in the + corresponding file in the $GIT_DIR/remotes/ directory + + URL: + Pull: refs/heads/master: + + while having # is equivalent to + + URL: + Pull: refs/heads/: + +:: + The canonical format of a parameter is + +?:; that is, an optional plus '+', followed + by the source ref, followed by a colon ':', followed by + the destination ref. + + When used in "git push", the side can be an + arbitrary "SHA1 expression" that can be used as an + argument to "git-cat-file -t". E.g. "master~4" (push + four parents before the current master head). + + For "git push", the local ref that matches is used + to fast forward the remote ref that matches . If + the optional plus '+' is used, the remote ref is updated + even if it does not result in a fast forward update. + + For "git fetch/pull", the remote ref that matches + is fetched, and if is not empty string, the local + ref that matches it is fast forwarded using . + Again, if the optional plus '+' is used, the local ref + is updated even if it does not result in a fast forward + update. + + Some short-cut notations are also supported. + + * For backward compatibility, "tag" is almost ignored; + it just makes the following parameter to mean a + refspec "refs/tags/:refs/tags/". + + * A parameter without a colon is equivalent to + : when pulling/fetching, and : when + pushing. That is, do not store it locally if + fetching, and update the same name if pushing. -- cgit v1.2.3 From c95173410d6f290e65c15232e56f4963f8279ef1 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Wed, 24 Aug 2005 16:46:11 -0700 Subject: Update tutorial to describe shared repository style a bit more. Signed-off-by: Junio C Hamano --- Documentation/tutorial.txt | 73 +++++++++++++++++++++++++++++++++------------- 1 file changed, 53 insertions(+), 20 deletions(-) diff --git a/Documentation/tutorial.txt b/Documentation/tutorial.txt index 876a4afd17..997e958259 100644 --- a/Documentation/tutorial.txt +++ b/Documentation/tutorial.txt @@ -892,18 +892,26 @@ pull from: It is likely that you will be pulling from the same remote repository from time to time. As a short hand, you can store -the remote repository URL in a file under .git/branches/ +the remote repository URL in a file under .git/remotes/ directory, like this: - mkdir -p .git/branches - echo rsync://kernel.org/pub/scm/git/git.git/ \ - >.git/branches/linus +------------------------------------------------ +mkdir -p .git/remotes/ +cat >.git/remotes/linus <<\EOF +URL: http://www.kernel.org/pub/scm/git/git.git/ +EOF +------------------------------------------------ and use the filename to "git pull" instead of the full URL. -The contents of a file under .git/branches can even be a prefix +The URL specified in such file can even be a prefix of a full URL, like this: - echo rsync://kernel.org/pub/.../jgarzik/ >.git/branches/jgarzik +------------------------------------------------ +cat >.git/remotes/jgarzik <<\EOF +URL: http://www.kernel.org/pub/scm/linux/git/jgarzik/ +EOF +------------------------------------------------ + Examples. @@ -913,9 +921,9 @@ Examples. the above are equivalent to: - (1) git pull rsync://kernel.org/pub/scm/git/git.git/ HEAD - (2) git pull rsync://kernel.org/pub/scm/git/git.git/ tag v0.99.1 - (3) git pull rsync://kernel.org/pub/.../jgarzik/netdev-2.6.git e100 + (1) git pull http://www.kernel.org/pub/scm/git/git.git/ HEAD + (2) git pull http://www.kernel.org/pub/scm/git/git.git/ tag v0.99.1 + (3) git pull http://www.kernel.org/pub/.../jgarzik/netdev-2.6.git e100 Publishing your work @@ -1169,18 +1177,43 @@ Working with Others, Shared Repository Style If you are coming from CVS background, the style of cooperation suggested in the previous section may be new to you. You do not have to worry. git supports "shared public repository" style of -cooperation you are more familiar with as well. - -For this, you should set up a public repository on a machine -that are reachable via SSH by people with "commit privileges". -Put them in the same user group and make the repository writable -by that group. Then, each committer would first merge with the -head of the branch of choice, and run "git push" to update the -branch at the public repository. "git push" refuses to update -if the reference on the remote side is not an ancestor of the -commit you are pushing, to prevent you from overwriting changes -made by somebody else. +cooperation you are probably more familiar with as well. + +For this, set up a public repository on a machine that is +reachable via SSH by people with "commit privileges". Put the +committers in the same user group and make the repository +writable by that group. + +Each committer would then: + + - clone the shared repository to a local repository, + +------------------------------------------------ +$ git clone repo.shared.xz:/pub/scm/project.git/ my-project +$ cd my-project +$ hack away +------------------------------------------------ + + - merge the work others might have done while you were + hacking away. + +------------------------------------------------ +$ git pull origin +$ test the merge result +------------------------------------------------ + + - push your work as the new head of the shared + repository. + +------------------------------------------------ +$ git push origin master +------------------------------------------------ +If somebody else pushed into the same shared repository while +you were working locally, the last step "git push" would +complain, telling you that the remote "master" head does not +fast forward. You need to pull and merge those other changes +back before you push your work when it happens. [ to be continued.. cvsimports ] -- cgit v1.2.3