{"thread":{"id":"5939","subject":"[RFC/PATCH] git-fetch: Use already fetched branch with the --local flag.","startedAt":"2006-10-16T13:40:42Z","lastAt":"2006-10-17T14:03:30Z","messageCount":4,"participants":["Santi Béjar","Junio C Hamano"],"isPatch":true,"patchVersion":1,"patchTotal":null},"messages":[{"id":"28843","messageId":"87ac3w8jl1.fsf@gmail.com","threadId":"5939","inReplyTo":null,"subject":"[RFC/PATCH] git-fetch: Use already fetched branch with the --local flag.","fromName":"Santi Béjar","fromEmail":"sbejar@gmail.com","sentAt":"2006-10-16T13:40:42Z","receivedAt":"2006-10-16T13:40:42Z","isPatch":true,"sender":{"key":"santi@agolina.net","avatar":null},"body":"\nIt allows to separate when you fetch from when you merge. So, a \"git pull\"\ncan be:\n\n$ git fetch\n$ git pull --local\n\nand the pull call can be made later. This is usefull when you have multiple\nbranches and you want to merge the same \"upstream\" branch, or when you are\noffline but you have already fetched the remote branch.\n\nNote that this is different from:\n\n$ git fetch\n$ git pull . origin\n\n(1) you do not have to tell explicitly the branch to merge\n(2) the commit message is exactly as with \"git pull\"\n\nSigned-off-by: Santi Béjar <sbejar@gmail.com>\n---\n Documentation/fetch-options.txt |    3 +++\n git-fetch.sh                    |   25 +++++++++++++++++++------\n git-parse-remote.sh             |   22 ++++++++++++++++++++++\n 3 files changed, 44 insertions(+), 6 deletions(-)\n\ndiff --git a/Documentation/fetch-options.txt b/Documentation/fetch-options.txt\nindex 13f34d3..3a6cb3d 100644\n--- a/Documentation/fetch-options.txt\n+++ b/Documentation/fetch-options.txt\n@@ -39,3 +39,6 @@\n \tcheck.  Note that fetching into the current branch will not\n \tupdate the index and working directory, so use it with care.\n \n+\\--local::\n+\tDo not fetch from the remote repository. Use the already fetched\n+\tbranches to program the merge for `git-pull`.\ndiff --git a/git-fetch.sh b/git-fetch.sh\nindex 79222fb..5ff800a 100755\n--- a/git-fetch.sh\n+++ b/git-fetch.sh\n@@ -21,6 +21,7 @@ update_head_ok=\n exec=\n upload_pack=\n keep=--thin\n+local_fetch=\n while case \"$#\" in 0) break ;; esac\n do\n \tcase \"$1\" in\n@@ -56,6 +57,9 @@ do\n \t--reflog-action=*)\n \t\trloga=`expr \"z$1\" : 'z-[^=]*=\\(.*\\)'`\n \t\t;;\n+\t--local)\n+\t\tlocal_fetch=t\n+\t\t;;\n \t-*)\n \t\tusage\n \t\t;;\n@@ -80,6 +84,10 @@ refs=\n rref=\n rsync_slurped_objects=\n \n+[ \"$local_fetch\" = t ] && [ \"$remote_nick\" = \"$remote\" ] && \\\n+    [ \"$remote\" != \".\" ] && \\\n+    die \"Flag --local only compatible with remote shorthands\"\n+\n rloga=\"$rloga $remote_nick\"\n test \"$remote_nick\" = \"$remote\" || rloga=\"$rloga $remote\"\n \n@@ -285,8 +293,8 @@ fetch_main () {\n       rref=\"$rref$LF$remote_name\"\n \n       # There are transports that can fetch only one head at a time...\n-      case \"$remote\" in\n-      http://* | https://* | ftp://*)\n+      case \"$local_fetch,$remote\" in\n+      ,http://* | ,https://* | ,ftp://*)\n \t  if [ -n \"$GIT_SSL_NO_VERIFY\" ]; then\n \t      curl_extra_args=\"-k\"\n \t  fi\n@@ -313,7 +321,7 @@ fetch_main () {\n \t  echo >&2 Fetching \"$remote_name from $remote\" using http\n \t  git-http-fetch -v -a \"$head\" \"$remote/\" || exit\n \t  ;;\n-      rsync://*)\n+      ,rsync://*)\n \t  TMP_HEAD=\"$GIT_DIR/TMP_HEAD\"\n \t  rsync -L -q \"$remote/$remote_name\" \"$TMP_HEAD\" || exit 1\n \t  head=$(git-rev-parse --verify TMP_HEAD)\n@@ -343,6 +351,11 @@ fetch_main () {\n \t      rsync_slurped_objects=t\n \t  }\n \t  ;;\n+      t,*)\n+\t  [ -z \"$local_name\" ] &&\\\n+\t\tlocal_name=$(get_ref_for_remote_branch \"$remote_nick\" \"$remote_name\")\n+\t  head=$(git-rev-parse --verify $local_name^0) || exit\n+\t  ;;\n       *)\n \t  # We will do git native transport with just one call later.\n \t  continue ;;\n@@ -353,8 +366,8 @@ fetch_main () {\n \n   done\n \n-  case \"$remote\" in\n-  http://* | https://* | ftp://* | rsync://* )\n+  case \"$local_fetch,$remote\" in\n+  ,http://* | ,https://* | ,ftp://* | ,rsync://* | t,*)\n       ;; # we are already done.\n   *)\n     ( : subshell because we muck with IFS\n@@ -406,7 +419,7 @@ fetch_main () {\n fetch_main \"$reflist\"\n \n # automated tag following\n-case \"$no_tags$tags\" in\n+case \"$no_tags$tags$local_fetch\" in\n '')\n \tcase \"$reflist\" in\n \t*:refs/*)\ndiff --git a/git-parse-remote.sh b/git-parse-remote.sh\nindex c325ef7..679f73c 100755\n--- a/git-parse-remote.sh\n+++ b/git-parse-remote.sh\n@@ -236,3 +236,25 @@ resolve_alternates () {\n \t\tesac\n \tdone\n }\n+\n+get_ref_for_remote_branch (){\n+\tdata_source=$(get_data_source \"$1\")\n+\tcase \"$data_source\" in\n+\t'' | config-partial | branches | branches-partial)\n+\t\ttest \"$1\" = . && echo $2\n+\t\t;;\n+\tconfig)\n+\t\tref=$(git-repo-config --get-all \"remote.$1.fetch\" |\\\n+\t\t\tgrep \"^$2:\")\n+\t\texpr \"z$ref\" : 'z[^:]*:\\(.*\\)'\n+\t\t;;\n+\tremotes)\n+\t\tref=$(sed -ne '/^Pull: */{\n+\t\t\t\ts///p\n+\t\t\t}' \"$GIT_DIR/remotes/$1\" | grep \"$2:\")\n+\t\texpr \"z$ref\" : 'z[^:]*:\\(.*\\)'\n+\t\t;;\n+\t*)\n+\t\tdie \"internal error: get-ref-for-remote-branch $1 $2\" ;;\n+\tesac\n+}\n-- \n1.4.3.rc2.ga442\n"},{"id":"28911","messageId":"7vbqobo1m1.fsf@assigned-by-dhcp.cox.net","threadId":"5939","inReplyTo":"87ac3w8jl1.fsf@gmail.com","subject":"Re: [RFC/PATCH] git-fetch: Use already fetched branch with the --local flag.","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2006-10-17T07:14:30Z","receivedAt":"2006-10-17T07:14:30Z","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> It allows to separate when you fetch from when you merge. So, a \"git pull\"\n> can be:\n>\n> $ git fetch\n> $ git pull --local\n\nThere was something that has been disturbing me in your patches\n(this one, and the previous \"remote=.\" one) and I could not tell\nwhat it was.  I think I know what it is now.\n\nLet me outline my understanding of the workflow these two\nchanges would help.\n\nYou have an upstream repository that has more than one branches\nyou are interested in, say \"master\" and \"next\".  And you work on\ntop of both of them, so you have two branches of your own that\ncorrespond to them.\n\nSo you organize your remote section perhaps like this:\n\n\t[remote.\"origin\"]\n        \turl = git://git.k.o/.../git.git/\n                fetch = refs/heads/master:refs/remotes/origin/master\n                fetch = refs/heads/next:refs/remotes/origin/next\n                fetch = +refs/heads/pu:refs/remotes/origin/pu\n\n\t[branch.\"master\"]\n        \tremote = origin\n                merge = refs/heads/master\n\n\t[branch.\"next\"]\n        \tremote = origin\n                merge = refs/heads/next\n\nThat is, your refs/heads/master corresponds to upstream's master\nbranch and your next corresponds to upstream's next branch.\nWhen you are on your \"master\" you would merge changes made to\nupstream's master into it with \"git pull\".\n\n        By the way, could you add descriptions on remote.* to\n        Documentation/config.txt?\n\nAfter doing a \"git pull\" while on your \"master\" and finishing\nworking on your \"master\", you might switch to your \"next\".  At\nthat point, if you want to merge upstream changes without\nre-fetching, you can do either of the following:\n\n\tgit pull . remotes/origin/next\n        git pull --local\n\n(the former can be \"git pull\" if \"branch.next.remote=.\").\n\nI think this is the point of your two patches, and in that\nsense, the --local one makes \"branch.remote=.\" patch\nunnecessary.\n\nWhile these save typing on \"git pull\", two things bother me.\n\n * the tool is not helping you decide if you can get away\n   without re-fetching.  you need to remember that (1) you\n   fetched from the upstream to update \"master\" recently _and_\n   (2) because of your [remote.\"origin\"] configuration your\n   remotes/origin/next was updated while you pulled into your\n   \"master\".\n\n * while the workflow assumes that one local branch is tied\n   closely to one remote branch (in this example, tracked under\n   remotes/origin), the rest of the tools do not take advantage\n   of that assumption to help you decide what to do next.\n\nFor example, if each of your local branch is tied closely to one\nremote branch, you should be able to \"git fetch\" to update the\ntracking branches and then ask:\n\n - what changes are in remote that I haven't merged?\n\n - what happens when I pull --local right now?\n\n - what changes if any are in mine alone missing from remote?\n\n - can I push to remote right now (i.e. would it fast-forward)?\n\n - how fresh is the tracking branch that corresponds to my\n   current branch?\n\nRight now, these require you to spell out the name of the\ntracking branch.  Assuming you are on your \"next\" branch:\n\n\tgit log ..remotes/origin/next\n        git log remotes/origin/next..\n        git log remotes/origin/next...next\t\t[*1*]\n\tgit show-branch remotes/origin/next next\n\ttail -n 1 .git/logs/remotes/origin/next\n\nwould be the ways to ask the above questions (and the last one\nis unreadable unless you can do strptime in your head).\n\nMaybe we can introduce a new extended SHA-1 notation to mean\n\"the tracking branch this branch usually merges from\".  Then we\ncan say:\n\n\tgit log ..^\n        git log ^..\n        git log ^...\n        git show-branch ^ next\n\nI am not sure '^' is syntactically viable, but hopefully you get\nthe idea.\n\n\n[*1*] While three-dots symmetric difference is a nice addition\nmade recently, I often find it irritating that the output does\nnot tell which branch each of the commit is reachable from, and\nend up running show-branch, which does.  Would anybody have a\nclever idea to fix this cleanly?\n"},{"id":"28921","messageId":"8aa486160610170136n28ef3f94q630127982156a115@mail.gmail.com","threadId":"5939","inReplyTo":"7vbqobo1m1.fsf@assigned-by-dhcp.cox.net","subject":"Re: [RFC/PATCH] git-fetch: Use already fetched branch with the --local flag.","fromName":"Santi Béjar","fromEmail":"sbejar@gmail.com","sentAt":"2006-10-17T08:36:35Z","receivedAt":"2006-10-17T08:36:35Z","isPatch":true,"sender":{"key":"santi@agolina.net","avatar":null},"body":"2006/10/17, Junio C Hamano <junkio@cox.net>:\n\n[...]\n\n>\n> You have an upstream repository that has more than one branches\n> you are interested in, say \"master\" and \"next\".  And you work on\n> top of both of them, so you have two branches of your own that\n> correspond to them.\n>\n> So you organize your remote section perhaps like this:\n>\n>         [remote.\"origin\"]\n>                 url = git://git.k.o/.../git.git/\n>                 fetch = refs/heads/master:refs/remotes/origin/master\n>                 fetch = refs/heads/next:refs/remotes/origin/next\n>                 fetch = +refs/heads/pu:refs/remotes/origin/pu\n>\n>         [branch.\"master\"]\n>                 remote = origin\n>                 merge = refs/heads/master\n>\n>         [branch.\"next\"]\n>                 remote = origin\n>                 merge = refs/heads/next\n>\n> That is, your refs/heads/master corresponds to upstream's master\n> branch and your next corresponds to upstream's next branch.\n> When you are on your \"master\" you would merge changes made to\n> upstream's master into it with \"git pull\".\n\nYes, that is.\n\n>\n>         By the way, could you add descriptions on remote.* to\n>         Documentation/config.txt?\n>\n\nI'll try. Off-topic: Do you want also docs for the ^@ notation and an\nimplementation in git-rev-parse?\n\n> After doing a \"git pull\" while on your \"master\" and finishing\n> working on your \"master\", you might switch to your \"next\".  At\n> that point, if you want to merge upstream changes without\n> re-fetching, you can do either of the following:\n>\n>         git pull . remotes/origin/next\n>         git pull --local\n>\n> (the former can be \"git pull\" if \"branch.next.remote=.\").\n>\n> I think this is the point of your two patches, and in that\n> sense, the --local one makes \"branch.remote=.\" patch\n> unnecessary.\n\nI see them differently. \"branch.remote=.\" is when there is no upstream\n(e.g., for your next and master branches in git.git).\n\n>\n> While these save typing on \"git pull\", two things bother me.\n>\n>  * the tool is not helping you decide if you can get away\n>    without re-fetching.  you need to remember that (1) you\n>    fetched from the upstream to update \"master\" recently _and_\n>    (2) because of your [remote.\"origin\"] configuration your\n>    remotes/origin/next was updated while you pulled into your\n>    \"master\".\n\nYou never know if you can get away without re-fetching (or I don't\nparse this sentence :). The way I see it, you always us \"git pull\"\nexcept when you want to merge the exactly the already fetch branch\nbecause (1) you want to merge the same upstream as with other branch\n(2) you don't have access to the remote repository (3)...\n\n>\n>  * while the workflow assumes that one local branch is tied\n>    closely to one remote branch (in this example, tracked under\n>    remotes/origin), the rest of the tools do not take advantage\n>    of that assumption to help you decide what to do next.\n\nThis is the next item in my TODO :)\nNext with a program similar to \"svn info\" showing misc info about a branch.\n\n>\n> For example, if each of your local branch is tied closely to one\n> remote branch, you should be able to \"git fetch\" to update the\n> tracking branches and then ask:\n>\n>  - what changes are in remote that I haven't merged?\n>\n>  - what happens when I pull --local right now?\n>\n>  - what changes if any are in mine alone missing from remote?\n>\n>  - can I push to remote right now (i.e. would it fast-forward)?\n>\n>  - how fresh is the tracking branch that corresponds to my\n>    current branch?\n>\n> Right now, these require you to spell out the name of the\n> tracking branch.  Assuming you are on your \"next\" branch:\n>\n>         git log ..remotes/origin/next\n>         git log remotes/origin/next..\n>         git log remotes/origin/next...next              [*1*]\n>         git show-branch remotes/origin/next next\n>         tail -n 1 .git/logs/remotes/origin/next\n>\n> would be the ways to ask the above questions (and the last one\n> is unreadable unless you can do strptime in your head).\n>\n> Maybe we can introduce a new extended SHA-1 notation to mean\n> \"the tracking branch this branch usually merges from\".  Then we\n> can say:\n>\n>         git log ..^\n>         git log ^..\n>         git log ^...\n>         git show-branch ^ next\n>\n> I am not sure '^' is syntactically viable, but hopefully you get\n> the idea.\n\nI get it. Another idea is to have a .git/ORIGIN that points to the\ntracking branch so you could say:\n\n         git log ..ORIGIN\n         git log ORIGIN..\n         git log ORIGIN...\n         git show-branch ORIGIN next\n\nOne advantage is that it only needs changes to \"git checkout\" (and\npossibly others but not to plumbing ones).\nAnother is that the ^ notation forces the low level tools to follow\nconfigs in [branch.\"...\"] and [remote.\"...\"].\n>\n>\n> [*1*] While three-dots symmetric difference is a nice addition\n> made recently, I often find it irritating that the output does\n> not tell which branch each of the commit is reachable from, and\n> end up running show-branch, which does.  Would anybody have a\n> clever idea to fix this cleanly?\n\nI don't know if it is a clever idea but...\n\nWe could use the git-name-rev method:\n\n$git log a...b\ncommit sha1 (a)\n....\n\ncommit sha1 (a^)\n....\n\ncommit sha1 (b^)\n....\n\ncommit sha1 (b)\n....\n\nand without this when on both branches.\n\nSanti\n"},{"id":"28959","messageId":"873b9n9gzx.fsf@gmail.com","threadId":"5939","inReplyTo":"87ac3w8jl1.fsf@gmail.com","subject":"Re: [RFC/PATCH] git-fetch: Use already fetched branch with the --local flag.","fromName":"Santi Béjar","fromEmail":"sbejar@gmail.com","sentAt":"2006-10-17T14:03:30Z","receivedAt":"2006-10-17T14:03:30Z","isPatch":true,"sender":{"key":"santi@agolina.net","avatar":null},"body":"\nPlease, add this:\n\ndiff --git a/git-parse-remote.sh b/git-parse-remote.sh\nindex 617d022..a792323 100755\n--- a/git-parse-remote.sh\n+++ b/git-parse-remote.sh\n@@ -260,7 +260,7 @@ get_ref_for_remote_branch (){\n \tremotes)\n \t\tref=$(sed -ne '/^Pull: */{\n \t\t\t\ts///p\n-\t\t\t}' \"$GIT_DIR/remotes/$1\" | grep \"$2:\")\n+\t\t\t}' \"$GIT_DIR/remotes/$1\" | grep \"^$2:\")\n \t\texpr \"z$ref\" : 'z[^:]*:\\(.*\\)'\n \t\t;;\n \t*)\n"}]}