{"thread":{"id":"6938","subject":"[PATCH] git-fetch: Split fetch and merge logic","startedAt":"2007-02-24T09:50:08Z","lastAt":"2007-02-24T10:23:15Z","messageCount":2,"participants":["Santi Béjar","Junio C Hamano"],"isPatch":true,"patchVersion":1,"patchTotal":null},"messages":[{"id":"35391","messageId":"87ps7zj35b.fsf@gmail.com","threadId":"6938","inReplyTo":null,"subject":"[PATCH] git-fetch: Split fetch and merge logic","fromName":"Santi Béjar","fromEmail":"sbejar@gmail.com","sentAt":"2007-02-24T09:50:08Z","receivedAt":"2007-02-24T09:50:08Z","isPatch":true,"sender":{"key":"santi@agolina.net","avatar":null},"body":"\nIt makes git-parse-remote.sh and almost all git-fetch independent\nof the merge logic.\n\ngit-fetch fetches the branches from the remote and saves this\ninformation in .git/FETCH_FETCHED (a temporary file), and at the end it\ngenerates the file .git/FETCH_HEAD.\n\nThe current merge behaviour is unchanged.\n\nSigned-off-by: Santi Béjar <sbejar@gmail.com>\n---\nHi *,\n\n  I've addressed all the comments, now prepared to even more comments :)\n\n  Junio, from your \"What's cooking in git.git (topics)\" I undestand that\n  the jc/fetch topic is not going to be in next soon (even for the first\n  commit?). Anyway, the simple question is: Which branch (or commit) you\n  want me to base this patch?\n\n git-fetch.sh        |   80 +++++++++++++++++++++++++++++++-------------------\n git-parse-remote.sh |   65 ++++++++++++-----------------------------\n 2 files changed, 68 insertions(+), 77 deletions(-)\n\ndiff --git a/git-fetch.sh b/git-fetch.sh\nindex d230995..fccfc7d 100755\n--- a/git-fetch.sh\n+++ b/git-fetch.sh\n@@ -77,9 +77,9 @@ do\n \tshift\n done\n \n+origin=$(get_default_remote)\n case \"$#\" in\n 0)\n-\torigin=$(get_default_remote)\n \ttest -n \"$(get_remote_url ${origin})\" ||\n \t\tdie \"Where do you want to fetch from today?\"\n \tset x $origin ; shift ;;\n@@ -101,6 +101,8 @@ if test \"\" = \"$append\"\n then\n \t: >\"$GIT_DIR/FETCH_HEAD\"\n fi\n+: >\"$GIT_DIR/FETCH_FETCHED\"\n+trap 'rm -f \"$GIT_DIR\"/FETCH_FETCHED' 0 1 2 3 15\n \n # Global that is reused later\n ls_remote_result=$(git ls-remote $exec \"$remote\") ||\n@@ -112,10 +114,6 @@ append_fetch_head () {\n     remote_name_=\"$3\"\n     remote_nick_=\"$4\"\n     local_name_=\"$5\"\n-    case \"$6\" in\n-    t) not_for_merge_='not-for-merge' ;;\n-    '') not_for_merge_= ;;\n-    esac\n \n     # remote-nick is the URL given on the command line (or a shorthand)\n     # remote-name is the $GIT_DIR relative refs/ path we computed\n@@ -146,9 +144,7 @@ append_fetch_head () {\n     if git-cat-file commit \"$head_\" >/dev/null 2>&1\n     then\n \theadc_=$(git-rev-parse --verify \"$head_^0\") || exit\n-\techo \"$headc_\t$not_for_merge_\t$note_\" >>\"$GIT_DIR/FETCH_HEAD\"\n-    else\n-\techo \"$head_\tnot-for-merge\t$note_\" >>\"$GIT_DIR/FETCH_HEAD\"\n+\techo \"$headc_\t$remote_name_:$local_name_\t$note_\" >>\"$GIT_DIR/FETCH_FETCHED\"\n     fi\n \n     update_local_ref \"$local_name_\" \"$head_\" \"$note_\"\n@@ -265,7 +261,7 @@ then\n \t\t  git-show-ref --exclude-existing=refs/tags/ |\n \t          while read sha1 name\n \t\t  do\n-\t\t\techo \".${name}:${name}\"\n+\t\t\techo \"${name}:${name}\"\n \t\t  done` || exit\n \tif test \"$#\" -gt 1\n \tthen\n@@ -288,13 +284,6 @@ fetch_main () {\n \n       # These are relative path from $GIT_DIR, typically starting at refs/\n       # but may be HEAD\n-      if expr \"z$ref\" : 'z\\.' >/dev/null\n-      then\n-\t  not_for_merge=t\n-\t  ref=$(expr \"z$ref\" : 'z\\.\\(.*\\)')\n-      else\n-\t  not_for_merge=\n-      fi\n       if expr \"z$ref\" : 'z+' >/dev/null\n       then\n \t  single_force=t\n@@ -375,7 +364,7 @@ fetch_main () {\n       esac\n \n       append_fetch_head \"$head\" \"$remote\" \\\n-\t  \"$remote_name\" \"$remote_nick\" \"$local_name\" \"$not_for_merge\" || exit\n+\t  \"$remote_name\" \"$remote_nick\" \"$local_name\" || exit\n \n   done\n \n@@ -418,28 +407,16 @@ fetch_main () {\n \t      case \"$ref\" in\n \t      +$remote_name:*)\n \t\t  single_force=t\n-\t\t  not_for_merge=\n-\t\t  found=\"$ref\"\n-\t\t  break ;;\n-\t      .+$remote_name:*)\n-\t\t  single_force=t\n-\t\t  not_for_merge=t\n-\t\t  found=\"$ref\"\n-\t\t  break ;;\n-\t      .$remote_name:*)\n-\t\t  not_for_merge=t\n \t\t  found=\"$ref\"\n \t\t  break ;;\n \t      $remote_name:*)\n-\t\t  not_for_merge=\n \t\t  found=\"$ref\"\n \t\t  break ;;\n \t      esac\n \t  done\n \t  local_name=$(expr \"z$found\" : 'z[^:]*:\\(.*\\)')\n \t  append_fetch_head \"$sha1\" \"$remote\" \\\n-\t\t  \"$remote_name\" \"$remote_nick\" \"$local_name\" \\\n-\t\t  \"$not_for_merge\" || exit\n+\t\t  \"$remote_name\" \"$remote_nick\" \"$local_name\" || exit\n         done\n       )\n     ) || exit ;;\n@@ -463,7 +440,7 @@ case \"$no_tags$tags\" in\n \t\tdo\n \t\t\tgit-cat-file -t \"$sha1\" >/dev/null 2>&1 || continue\n \t\t\techo >&2 \"Auto-following $name\"\n-\t\t\techo \".${name}:${name}\"\n+\t\t\techo \"${name}:${name}\"\n \t\tdone)\n \tesac\n \tcase \"$taglist\" in\n@@ -491,3 +468,44 @@ case \"$orig_head\" in\n \tfi\n \t;;\n esac\n+\n+# Generate $GIT_DIR/FETCH_HEAD\n+case \",$#,$remote_nick,\" in\n+,1,$origin,)\n+\tcurr_branch=$(git-symbolic-ref -q HEAD | sed -e 's|^refs/heads/||')\n+\tmerge_branches=$(git-config \\\n+\t\t--get-all \"branch.${curr_branch}.merge\" | sort -u)\n+\tfetch_branches=$(get_remote_default_refs_for_fetch -n $remote_nick |\n+\t\tsed -e 's/:.*$//g' -e 's/^+//' | sort -u)\n+\ttest -n \"$merge_branches\" && test -n \"$fetch_branches\" &&\n+\tmerge_branches=$(printf '%s\\n%s' \"$merge_branches\" \"$fetch_branches\" | sort | uniq -d)\n+\t[ -z \"$merge_branches\" ] ||\n+\ttest \"$(get_data_source $remote_nick)\" = branches && merge_first=yes;;\n+,1,$remote,) merge_branches=HEAD;;\n+,1,*)merge_first=yes ;;\n+*)\n+\tshift\n+\tmerge_branches=$(for ref; do\n+\t\texpr \"z$ref\" : 'z.*:' >/dev/null || ref=\"${ref}:\"\n+\t\techo \"$(expr \"z$ref\" : 'z\\([^:]*\\):')\"; done);;\n+esac\n+\n+test \"$merge_first\" = \"yes\" &&\n+test \"$(get_remote_default_refs_for_fetch -t $remote_nick)\" != \"explicit\" &&\n+merge_branches= && merge_first=\n+\n+merge_branches=$(canon_refs_list_for_fetch $merge_branches | sed 's/:.*$//g')\n+\n+while IFS='\t' read sha1 ref note ; do\n+\tremote_branch=$(expr \"z$ref\" : 'z\\([^:]*\\):')\n+\tfor merge_branch in $merge_branches ; do\n+\t\t[ \"$merge_branch\" = \"$remote_branch\" ] &&\n+\t\t\techo \"$sha1\t\t$note\" && continue 2\n+\tdone\n+\tif ! test \"$merge_first\" || test \"$merge_first\" = \"done\" ; then\n+\t\techo \"$sha1\tnot-for-merge\t$note\"\n+\telse\n+\t\techo \"$sha1\t\t$note\"\n+\t\tmerge_first=done\n+\tfi\n+done < \"$GIT_DIR\"/FETCH_FETCHED >> \"$GIT_DIR/FETCH_HEAD\"\ndiff --git a/git-parse-remote.sh b/git-parse-remote.sh\nindex 5208ee6..307ab06 100755\n--- a/git-parse-remote.sh\n+++ b/git-parse-remote.sh\n@@ -70,8 +70,7 @@ get_remote_default_refs_for_push () {\n \tesac\n }\n \n-# Called from canon_refs_list_for_fetch -d \"$remote\", which\n-# is called from get_remote_default_refs_for_fetch to grok\n+# Called from get_remote_default_refs_for_fetch to grok\n # refspecs that are retrieved from the configuration, but not\n # from get_remote_refs_for_fetch when it deals with refspecs\n # supplied on the command line.  $ls_remote_result has the list\n@@ -130,30 +129,6 @@ expand_refs_wildcard () {\n \n # Subroutine to canonicalize remote:local notation.\n canon_refs_list_for_fetch () {\n-\t# If called from get_remote_default_refs_for_fetch\n-\t# leave the branches in branch.${curr_branch}.merge alone,\n-\t# or the first one otherwise; add prefix . to the rest\n-\t# to prevent the secondary branches to be merged by default.\n-\tmerge_branches=\n-\tcurr_branch=\n-\tif test \"$1\" = \"-d\"\n-\tthen\n-\t\tshift ; remote=\"$1\" ; shift\n-\t\tset $(expand_refs_wildcard \"$remote\" \"$@\")\n-\t\tis_explicit=\"$1\"\n-\t\tshift\n-\t\tif test \"$remote\" = \"$(get_default_remote)\"\n-\t\tthen\n-\t\t\tcurr_branch=$(git-symbolic-ref -q HEAD | \\\n-\t\t\t    sed -e 's|^refs/heads/||')\n-\t\t\tmerge_branches=$(git-config \\\n-\t\t\t    --get-all \"branch.${curr_branch}.merge\")\n-\t\tfi\n-\t\tif test -z \"$merge_branches\" && test $is_explicit != explicit\n-\t\tthen\n-\t\t\tmerge_branches=..this.will.never.match.any.ref..\n-\t\tfi\n-\tfi\n \tfor ref\n \tdo\n \t\tforce=\n@@ -166,18 +141,6 @@ canon_refs_list_for_fetch () {\n \t\texpr \"z$ref\" : 'z.*:' >/dev/null || ref=\"${ref}:\"\n \t\tremote=$(expr \"z$ref\" : 'z\\([^:]*\\):')\n \t\tlocal=$(expr \"z$ref\" : 'z[^:]*:\\(.*\\)')\n-\t\tdot_prefix=.\n-\t\tif test -z \"$merge_branches\"\n-\t\tthen\n-\t\t\tmerge_branches=$remote\n-\t\t\tdot_prefix=\n-\t\telse\n-\t\t\tfor merge_branch in $merge_branches\n-\t\t\tdo\n-\t\t\t    [ \"$remote\" = \"$merge_branch\" ] &&\n-\t\t\t    dot_prefix= && break\n-\t\t\tdone\n-\t\tfi\n \t\tcase \"$remote\" in\n \t\t'' | HEAD ) remote=HEAD ;;\n \t\trefs/heads/* | refs/tags/* | refs/remotes/*) ;;\n@@ -196,32 +159,42 @@ canon_refs_list_for_fetch () {\n \t\t   git-check-ref-format \"$local_ref_name\" ||\n \t\t   die \"* refusing to create funny ref '$local_ref_name' locally\"\n \t\tfi\n-\t\techo \"${dot_prefix}${force}${remote}:${local}\"\n+\t\techo \"${force}${remote}:${local}\"\n \tdone\n }\n \n # Returns list of src: (no store), or src:dst (store)\n get_remote_default_refs_for_fetch () {\n+\ttest \"$1\" = -t && type=yes && shift\n+\ttest \"$1\" = -n && canon=no && shift\n \tdata_source=$(get_data_source \"$1\")\n \tcase \"$data_source\" in\n \t'')\n-\t\techo \"HEAD:\" ;;\n+\t\tset explicit \"HEAD:\" ;;\n \tconfig)\n-\t\tcanon_refs_list_for_fetch -d \"$1\" \\\n-\t\t\t$(git-config --get-all \"remote.$1.fetch\") ;;\n+\t\tset $(expand_refs_wildcard \"$1\" \\\n+\t\t\t$(git-config --get-all \"remote.$1.fetch\")) ;;\n \tbranches)\n \t\tremote_branch=$(sed -ne '/#/s/.*#//p' \"$GIT_DIR/branches/$1\")\n \t\tcase \"$remote_branch\" in '') remote_branch=master ;; esac\n-\t\techo \"refs/heads/${remote_branch}:refs/heads/$1\"\n+\t\tset explicit \"refs/heads/${remote_branch}:refs/heads/$1\"\n \t\t;;\n \tremotes)\n-\t\tcanon_refs_list_for_fetch -d \"$1\" $(sed -ne '/^Pull: */{\n-\t\t\t\t\t\ts///p\n-\t\t\t\t\t}' \"$GIT_DIR/remotes/$1\")\n+\t\tset $(expand_refs_wildcard \"$1\" $(sed -ne '/^Pull: */s///p'\\\n+\t\t\t\t\t\"$GIT_DIR/remotes/$1\"))\n \t\t;;\n \t*)\n \t\tdie \"internal error: get-remote-default-ref-for-push $1\" ;;\n \tesac\n+\tif test \"$type\" = yes ; then\n+\t\techo $1\n+\telif test \"$canon\" = no ; then\n+\t\tshift\n+\t\tfor ref ; do echo \"$ref\" ; done\n+\telse\n+\t\tshift\n+\t\tcanon_refs_list_for_fetch \"$@\"\n+\tfi\n }\n \n get_remote_refs_for_push () {\n-- \n1.5.0.1.576.g78541\n"},{"id":"35392","messageId":"7v8xenzwfg.fsf@assigned-by-dhcp.cox.net","threadId":"6938","inReplyTo":"87ps7zj35b.fsf@gmail.com","subject":"Re: [PATCH] git-fetch: Split fetch and merge logic","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2007-02-24T10:23:15Z","receivedAt":"2007-02-24T10:23:15Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Santi Béjar <sbejar@gmail.com> writes:\n\n>   I've addressed all the comments, now prepared to even more comments :)\n>\n>   Junio, from your \"What's cooking in git.git (topics)\" I undestand that\n>   the jc/fetch topic is not going to be in next soon (even for the first\n>   commit?). Anyway, the simple question is: Which branch (or commit) you\n>   want me to base this patch?\n\nFor now this is fine.\n\nI might have to postpone rebasing jc/fetch on top of this one\ndepending on my workload, but I'd want this clean-up first.\n\nThanks.\n"}]}