From: "Santi Béjar" <sbejar@gmail.com>
To: Git Mailing List <git@vger.kernel.org>
Subject: [PATCH] git-fetch: Split fetch and merge logic
Date: Wed, 07 Mar 2007 13:25:28 +0100 [thread overview]
Message-ID: <87fy8h5jgn.fsf@gmail.com> (raw)
It makes git-parse-remote.sh, git-fetch--tool and almost all git-fetch
independent of the merge logic.
git-fetch fetches the branches from the remote and saves this
information in .git/FETCH_FETCHED (a temporary file), and at the end it
generates the file .git/FETCH_HEAD.
The current merge behaviour is unchanged.
Signed-off-by: Santi Béjar <sbejar@gmail.com>
---
Hi *,
this time the net effect is to add 10 lines :(
This applies to next.
Regards,
Santi
builtin-fetch--tool.c | 49 ++++++++++--------------------
git-fetch.sh | 78 +++++++++++++++++++++++++++++++++++++++++-------
git-parse-remote.sh | 65 ++++++++++++-----------------------------
3 files changed, 101 insertions(+), 91 deletions(-)
diff --git a/builtin-fetch--tool.c b/builtin-fetch--tool.c
index e9d6764..2cee058 100644
--- a/builtin-fetch--tool.c
+++ b/builtin-fetch--tool.c
@@ -138,8 +138,7 @@ static int update_local_ref(const char *name,
static int append_fetch_head(FILE *fp,
const char *head, const char *remote,
- const char *remote_name, const char *remote_nick,
- const char *local_name, int not_for_merge,
+ const char *remote_name, const char *local_name,
int verbose, int force)
{
struct commit *commit;
@@ -151,8 +150,6 @@ static int append_fetch_head(FILE *fp,
if (get_sha1(head, sha1))
return error("Not a valid object name: %s", head);
commit = lookup_commit_reference(sha1);
- if (!commit)
- not_for_merge = 1;
if (!strcmp(remote_name, "HEAD")) {
kind = "";
@@ -189,9 +186,9 @@ static int append_fetch_head(FILE *fp,
note_len += sprintf(note + note_len, "'%s' of ", what);
}
note_len += sprintf(note + note_len, "%.*s", remote_len, remote);
- fprintf(fp, "%s\t%s\t%s\n",
+ fprintf(fp, "%s\t%s:%s\t%s\n",
sha1_to_hex(commit ? commit->object.sha1 : sha1),
- not_for_merge ? "not-for-merge" : "",
+ remote_name, local_name,
note);
return update_local_ref(local_name, head, note, verbose, force);
}
@@ -211,14 +208,14 @@ static void remove_keep_on_signal(int signo)
}
static char *find_local_name(const char *remote_name, const char *refs,
- int *force_p, int *not_for_merge_p)
+ int *force_p)
{
const char *ref = refs;
int len = strlen(remote_name);
while (ref) {
const char *next;
- int single_force, not_for_merge;
+ int single_force;
while (*ref == '\n')
ref++;
@@ -226,19 +223,11 @@ static char *find_local_name(const char *remote_name, const char *refs,
break;
next = strchr(ref, '\n');
- single_force = not_for_merge = 0;
+ single_force = 0;
if (*ref == '+') {
single_force = 1;
ref++;
}
- if (*ref == '.') {
- not_for_merge = 1;
- ref++;
- if (*ref == '+') {
- single_force = 1;
- ref++;
- }
- }
if (!strncmp(remote_name, ref, len) && ref[len] == ':') {
const char *local_part = ref + len + 1;
char *ret;
@@ -252,7 +241,6 @@ static char *find_local_name(const char *remote_name, const char *refs,
memcpy(ret, local_part, retlen);
ret[retlen] = 0;
*force_p = single_force;
- *not_for_merge_p = not_for_merge;
return ret;
}
ref = next;
@@ -262,7 +250,6 @@ static char *find_local_name(const char *remote_name, const char *refs,
static int fetch_native_store(FILE *fp,
const char *remote,
- const char *remote_nick,
const char *refs,
int verbose, int force)
{
@@ -276,7 +263,7 @@ static int fetch_native_store(FILE *fp,
int len;
char *cp;
char *local_name;
- int single_force, not_for_merge;
+ int single_force;
for (cp = buffer; *cp && !isspace(*cp); cp++)
;
@@ -298,12 +285,11 @@ static int fetch_native_store(FILE *fp,
}
local_name = find_local_name(cp, refs,
- &single_force, ¬_for_merge);
+ &single_force);
if (!local_name)
continue;
err |= append_fetch_head(fp,
- buffer, remote, cp, remote_nick,
- local_name, not_for_merge,
+ buffer, remote, cp, local_name,
verbose, force || single_force);
}
return err;
@@ -336,8 +322,6 @@ static int parse_reflist(const char *reflist)
break;
for (next = ref; *next && !isspace(*next); next++)
;
- if (*ref == '.')
- ref++;
if (*ref == '+')
ref++;
colon = strchr(ref, ':');
@@ -460,12 +444,11 @@ int cmd_fetch__tool(int argc, const char **argv, const char *prefix)
int result;
FILE *fp;
- if (argc != 8)
- return error("append-fetch-head takes 6 args");
- fp = fopen(git_path("FETCH_HEAD"), "a");
+ if (argc != 6)
+ return error("append-fetch-head takes 4 args");
+ fp = fopen(git_path("FETCH_FETCHED"), "a");
result = append_fetch_head(fp, argv[2], argv[3],
argv[4], argv[5],
- argv[6], !!argv[7][0],
verbose, force);
fclose(fp);
return result;
@@ -474,10 +457,10 @@ int cmd_fetch__tool(int argc, const char **argv, const char *prefix)
int result;
FILE *fp;
- if (argc != 5)
- return error("fetch-native-store takes 3 args");
- fp = fopen(git_path("FETCH_HEAD"), "a");
- result = fetch_native_store(fp, argv[2], argv[3], argv[4],
+ if (argc != 4)
+ return error("fetch-native-store takes 2 args");
+ fp = fopen(git_path("FETCH_FETCHED"), "a");
+ result = fetch_native_store(fp, argv[2], argv[3],
verbose, force);
fclose(fp);
return result;
diff --git a/git-fetch.sh b/git-fetch.sh
index 9d45dd2..58cbef1 100755
--- a/git-fetch.sh
+++ b/git-fetch.sh
@@ -79,9 +79,9 @@ do
shift
done
+origin=$(get_default_remote)
case "$#" in
0)
- origin=$(get_default_remote)
test -n "$(get_remote_url ${origin})" ||
die "Where do you want to fetch from today?"
set x $origin ; shift ;;
@@ -103,6 +103,8 @@ if test "" = "$append"
then
: >"$GIT_DIR/FETCH_HEAD"
fi
+: >"$GIT_DIR/FETCH_FETCHED"
+trap 'rm -f "$GIT_DIR"/FETCH_FETCHED' 0 1 2 3 15
# Global that is reused later
ls_remote_result=$(git ls-remote $exec "$remote") ||
@@ -145,7 +147,7 @@ then
git-show-ref --exclude-existing=refs/tags/ |
while read sha1 name
do
- echo ".${name}:${name}"
+ echo "${name}:${name}"
done` || exit
if test "$#" -gt 1
then
@@ -182,7 +184,7 @@ fetch_native () {
test -n "$force" && flags="$flags -f"
GIT_REFLOG_ACTION="$GIT_REFLOG_ACTION" \
git-fetch--tool $flags native-store \
- "$remote" "$remote_nick" "$refs"
+ "$remote" "$refs"
)
) || exit
@@ -199,13 +201,6 @@ fetch_dumb () {
# These are relative path from $GIT_DIR, typically starting at refs/
# but may be HEAD
- if expr "z$ref" : 'z\.' >/dev/null
- then
- not_for_merge=t
- ref=$(expr "z$ref" : 'z\.\(.*\)')
- else
- not_for_merge=
- fi
if expr "z$ref" : 'z+' >/dev/null
then
single_force=t
@@ -283,7 +278,7 @@ fetch_dumb () {
esac
append_fetch_head "$head" "$remote" \
- "$remote_name" "$remote_nick" "$local_name" "$not_for_merge" || exit
+ "$remote_name" "$remote_nick" "$local_name" || exit
done
@@ -316,7 +311,7 @@ case "$no_tags$tags" in
do
git-cat-file -t "$sha1" >/dev/null 2>&1 || continue
echo >&2 "Auto-following $name"
- echo ".${name}:${name}"
+ echo "${name}:${name}"
done)
esac
case "$taglist" in
@@ -344,3 +339,62 @@ case "$orig_head" in
fi
;;
esac
+# Generate $GIT_DIR/FETCH_HEAD
+case ",$#,$remote_nick," in
+,1,$origin,)
+ # Fetch default: merge the branches in branch.*.merge that match
+ # the fetched ones or the first one
+ curr_branch=$(git-symbolic-ref -q HEAD | sed -e 's|^refs/heads/||')
+ merge_branches=$(git-config \
+ --get-all "branch.${curr_branch}.merge" | sort -u)
+ fetch_branches=$(get_remote_default_refs_for_fetch -n $remote_nick |
+ sed -e 's/:.*$//g' -e 's/^+//' | sort -u)
+ test -n "$merge_branches" && test -n "$fetch_branches" &&
+ merge_branches=$(printf '%s\n%s' "$merge_branches" "$fetch_branches" |
+ sort | uniq -d)
+
+ [ -z "$merge_branches" ] ||
+ test "$(get_data_source $remote_nick)" = branches && merge_first=yes;;
+,1,$remote,)
+ # Remote is a URL, merge the default branch HEAD
+ merge_branches=HEAD;;
+,1,*)
+ # Remote is a shorthand diferent from the default,
+ # merge the first fetched branch
+ merge_first=yes ;;
+*)
+ # Merge the branches given in the command line
+ merge_branches=$(for ref in $(get_remote_refs_for_fetch "$@") ; do
+ expr "z$ref" : 'z.*:' >/dev/null || ref="${ref}:"
+ echo "$(expr "z$ref" : 'z\([^:]*\):')"; done);;
+esac
+
+if test "$merge_first" = "yes" ; then
+ merge_branches=
+ # Do not merge the first branch if it was specified with a glob
+ test "$(get_remote_default_refs_for_fetch -t $remote_nick)" != "explicit" &&
+ merge_first=
+else
+ merge_branches=$(canon_refs_list_for_fetch $merge_branches | sed 's/:.*$//g')
+fi
+
+while IFS=' ' read hash ref note ; do
+ # 2.6.11-tree tag would not be happy to be fed to resolve.
+ if git-cat-file commit "$hash" >/dev/null 2>&1
+ then
+ hashc=$(git-rev-parse --verify "$hash^0") || exit
+ remote_branch=$(expr "z$ref" : 'z\([^:]*\):')
+ for merge_branch in $merge_branches ; do
+ [ "$merge_branch" = "$remote_branch" ] &&
+ echo "$hashc $note" && continue 2
+ done
+ else
+ echo "$hash not-for-merge $note" && continue
+ fi
+ if ! test "$merge_first" || test "$merge_first" = "done" ; then
+ echo "$hash not-for-merge $note"
+ else
+ echo "$hash $note"
+ merge_first=done
+ fi
+done < "$GIT_DIR"/FETCH_FETCHED >> "$GIT_DIR/FETCH_HEAD"
diff --git a/git-parse-remote.sh b/git-parse-remote.sh
index c46131f..99e7184 100755
--- a/git-parse-remote.sh
+++ b/git-parse-remote.sh
@@ -70,8 +70,7 @@ get_remote_default_refs_for_push () {
esac
}
-# Called from canon_refs_list_for_fetch -d "$remote", which
-# is called from get_remote_default_refs_for_fetch to grok
+# Called from get_remote_default_refs_for_fetch to grok
# refspecs that are retrieved from the configuration, but not
# from get_remote_refs_for_fetch when it deals with refspecs
# supplied on the command line. $ls_remote_result has the list
@@ -87,30 +86,6 @@ expand_refs_wildcard () {
# Subroutine to canonicalize remote:local notation.
canon_refs_list_for_fetch () {
- # If called from get_remote_default_refs_for_fetch
- # leave the branches in branch.${curr_branch}.merge alone,
- # or the first one otherwise; add prefix . to the rest
- # to prevent the secondary branches to be merged by default.
- merge_branches=
- curr_branch=
- if test "$1" = "-d"
- then
- shift ; remote="$1" ; shift
- set $(expand_refs_wildcard "$remote" "$@")
- is_explicit="$1"
- shift
- if test "$remote" = "$(get_default_remote)"
- then
- curr_branch=$(git-symbolic-ref -q HEAD | \
- sed -e 's|^refs/heads/||')
- merge_branches=$(git-config \
- --get-all "branch.${curr_branch}.merge")
- fi
- if test -z "$merge_branches" && test $is_explicit != explicit
- then
- merge_branches=..this.will.never.match.any.ref..
- fi
- fi
for ref
do
force=
@@ -123,18 +98,6 @@ canon_refs_list_for_fetch () {
expr "z$ref" : 'z.*:' >/dev/null || ref="${ref}:"
remote=$(expr "z$ref" : 'z\([^:]*\):')
local=$(expr "z$ref" : 'z[^:]*:\(.*\)')
- dot_prefix=.
- if test -z "$merge_branches"
- then
- merge_branches=$remote
- dot_prefix=
- else
- for merge_branch in $merge_branches
- do
- [ "$remote" = "$merge_branch" ] &&
- dot_prefix= && break
- done
- fi
case "$remote" in
'' | HEAD ) remote=HEAD ;;
refs/heads/* | refs/tags/* | refs/remotes/*) ;;
@@ -153,32 +116,42 @@ canon_refs_list_for_fetch () {
git-check-ref-format "$local_ref_name" ||
die "* refusing to create funny ref '$local_ref_name' locally"
fi
- echo "${dot_prefix}${force}${remote}:${local}"
+ echo "${force}${remote}:${local}"
done
}
# Returns list of src: (no store), or src:dst (store)
get_remote_default_refs_for_fetch () {
+ test "$1" = -t && type=yes && shift
+ test "$1" = -n && canon=no && shift
data_source=$(get_data_source "$1")
case "$data_source" in
'')
- echo "HEAD:" ;;
+ set explicit "HEAD:" ;;
config)
- canon_refs_list_for_fetch -d "$1" \
- $(git-config --get-all "remote.$1.fetch") ;;
+ set $(expand_refs_wildcard "$1" \
+ $(git-config --get-all "remote.$1.fetch")) ;;
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"
+ set explicit "refs/heads/${remote_branch}:refs/heads/$1"
;;
remotes)
- canon_refs_list_for_fetch -d "$1" $(sed -ne '/^Pull: */{
- s///p
- }' "$GIT_DIR/remotes/$1")
+ set $(expand_refs_wildcard "$1" $(sed -ne '/^Pull: */s///p'\
+ "$GIT_DIR/remotes/$1"))
;;
*)
die "internal error: get-remote-default-ref-for-push $1" ;;
esac
+ if test "$type" = yes ; then
+ echo $1
+ elif test "$canon" = no ; then
+ shift
+ for ref ; do echo "$ref" ; done
+ else
+ shift
+ canon_refs_list_for_fetch "$@"
+ fi
}
get_remote_refs_for_push () {
--
1.5.0.3.897.g91a70-dirty
next reply other threads:[~2007-03-07 12:25 UTC|newest]
Thread overview: 3+ messages / expand[flat|nested] mbox.gz Atom feed top
2007-03-07 12:25 Santi Béjar [this message]
-- strict thread matches above, loose matches on Subject: below --
2007-02-24 9:50 [PATCH] git-fetch: Split fetch and merge logic Santi Béjar
2007-02-24 10:23 ` Junio C Hamano
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=87fy8h5jgn.fsf@gmail.com \
--to=sbejar@gmail.com \
--cc=git@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.