{"thread":{"id":"43574","subject":"Re: [DRAFT] Branching and merging with git","startedAt":"2006-11-16T23:47:19Z","lastAt":"2006-11-17T01:31:23Z","messageCount":3,"participants":["Junio C Hamano","linux@horizon.com"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"297738","messageId":"7vslgj2bug.fsf@assigned-by-dhcp.cox.net","threadId":"43574","inReplyTo":"20061116221701.4499.qmail@science.horizon.com","subject":"Re: [DRAFT] Branching and merging with git","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2006-11-16T23:47:19Z","receivedAt":"2006-11-16T23:47:19Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"linux@horizon.com writes:\n\n> I know it took me a while to get used to playing with branches, and I\n> still get nervous when doing something creative.  So I've been trying\n> to get more comfortable, and wrote the following to document what I've\n> learned.\n>\n> It's a first draft - I just finished writing it, so there are probably\n> some glaring errors - but I thought it might be of interest anyway.\n\nThis is a greatest write-up I've seen for the past several\nmonths.  I find it very balanced to point out the quirks people\nwould find difficult and explain why things are so by including\nhistorical notes in appropriate places when needed.  Definitely\nDocumentation/ material when copyediting is done.\n\nI have finished only the first half because it's not my git day\ntoday, but so far...\n\n> * Naming revisions\n>...\n> Second, you can refer to a head or tag name.  Git looks in the\n> following places, in order, for a head:\n> \t1) .git\n> \t2) .git/refs\n> \t3) .git/refs/heads\n> \t4) .git/refs/tags\n\nYou might want to check this with the array in sha1_name.c::get_sha1_basic().\nI think tags comes earlier than heads.\n\n> 2) Revert changes to a small number of files.\n>\n> \tgit checkout [<revision>] [--] <paths>\n>    will copy the version of the <paths> from the index to the working\n>    directory.  If a <revision> is given, the index for those paths will\n>    be updated from the given revision before copying from the index to\n>    the working tree.\n>\n>    Unlike the version with no <paths> specified, this does NOT update\n>    HEAD, even if <paths> is \".\".\n\nIt's great that you talk correctly about the latest feature-fix\nthat is queued for maint but not yet pushed out.\n\n> 2) By path name.  This is a feature which appears to be unique to git.\n>    If you give git-rev-list (or git-log, or gitk, or qgit) a list of\n>    pathname prefixes, it will list only commits which touch those\n>    paths. So \"git log drivers/scsi include/scsi\" will list only\n>    commits which alters a file whose name begins with drivers/scsi\n>    or include/scsi.\n>\n>    (If there's any possible ambiguity between a path name and a commit\n>    name, git-rev-list will refuse to proceed.  You can resolve it by\n>    including \"--\" on the command line.  Everything before that is a\n>    commit name; everything after is a path.)\n>\n>    This filter is in addition to the ancestry filter.  It's also rather\n>    clever about omitting unnecessary detail.  In particular, if there's\n>    a side branch which does touch drivers/scsi, then the entire branch,\n>    and the merge at the end, will be removed from the log.\n\n\"If there's a side branch which does NOT touch the paths...\" I think.\n\n> * Alternate branch naming\n>\n> The original git scheme mixes tracking branches with all the other heads.\n> This requires that you remember which branches are tracking branches and\n> which aren't.  Hopefully, you remember what all your branches are for,\n> but if you track a lot of remote repositories, you might not remember\n> what every remote branch is for and what you called it locally.\n\nI think you wanted to mention .git/refs/remotes hierarchy and\nseparate-remote here, but haven't elaborated yet...\n\n> * Remote tags\n>\n> TODO: Figure out how remote tags work, under what circumstances\n> they are fetched, and what git does if there are conflicts.\n\nrefs/tags namespace is not policed at all by git and is treated\nas a global namespace, controlled mostly by social convention\nthat your \"upstream\" (or central distribution point) supplies\ntags for people who use it to synchronize to share.  Also, since\nthere is no guarantee that tags point at commits (v2.6.11-tree\ntag is a pointer to a tree object, for example), there is no\nfarst-forward check performed for them.\n\nThe rule we use to autofollow tags currently is:\n\nWhen you use shorthand fetch (or pull), we find tags that do not\nexist locally, and if the object they point at are already found\nin the repository then we fetch them automatically.  So for\nexample, if you are only tracking my 'maint' and not 'master'\nnor 'next', and if you have tags up to v1.4.3.2, your \"git fetch\norigin\" would update your copy of 'maint' and bring the commits\nreachable from the tip of my 'maint'.  After that it notices\nthat v1.4.3.3, v1.4.3.4, v1.4.3.5 tags are in my repository but\nmissing from yours. It also notices that now you have\nv1.4.3.3^{}, v1.4.3.4^{} and v1.4.3.5^{} in your repository, so\nit issues another round of \"git fetch\" internally to fetch these\nthree tags.  At the same time it would also notice that I have\nv1.4.4 tag that you do not have, but v1.4.4^0 commit is not\nsomething you would get by fetching 'maint', so it would not\nfetch it automatically.\n"},{"id":"298034","messageId":"20061117011319.6738.qmail@science.horizon.com","threadId":"43574","inReplyTo":"7vslgj2bug.fsf@assigned-by-dhcp.cox.net","subject":"Re: [DRAFT] Branching and merging with git","fromName":"","fromEmail":"linux@horizon.com","sentAt":"2006-11-17T01:13:19Z","receivedAt":"2006-11-17T01:13:19Z","isPatch":false,"sender":{"key":"linux@horizon.com","avatar":null},"body":"> I find it very balanced to point out the quirks people\n> would find difficult and explain why things are so by including\n> historical notes in appropriate places when needed.\n\nI'm trying; I've been following git since day 1, so occasionally an\nobsolete fact gets stuck in my head.\n\nIf anyone has any advice on how and why one would invoke git-merge\ndirectly (the one why I know is to do a >2-way merge), that would\nbe appreciated.\n\n> I have finished only the first half because it's not my git day\n> today, but so far...\n\nWell, thank you for your time!\n\n>> * Naming revisions\n>>...\n>> Second, you can refer to a head or tag name.  Git looks in the\n>> following places, in order, for a head:\n>> \t1) .git\n>> \t2) .git/refs\n>> \t3) .git/refs/heads\n>> \t4) .git/refs/tags\n> \n> You might want to check this with the array in sha1_name.c::get_sha1_basic().\n> I think tags comes earlier than heads.\n\nQuite right.  It's\n\n        static const char *fmt[] = {\n                \"%.*s\",\n                \"refs/%.*s\",\n                \"refs/tags/%.*s\",\n                \"refs/heads/%.*s\",\n                \"refs/remotes/%.*s\",\n                \"refs/remotes/%.*s/HEAD\",\n                NULL\n        };\n\n>> 2) Revert changes to a small number of files.\n>>\n>> \tgit checkout [<revision>] [--] <paths>\n>>    will copy the version of the <paths> from the index to the working\n>>    directory.  If a <revision> is given, the index for those paths will\n>>    be updated from the given revision before copying from the index to\n>>    the working tree.\n>>\n>>    Unlike the version with no <paths> specified, this does NOT update\n>>    HEAD, even if <paths> is \".\".\n> \n> It's great that you talk correctly about the latest feature-fix\n> that is queued for maint but not yet pushed out.\n\nUm... there's a fix in there?  I thought that's how it always worked.\n\n> \"If there's a side branch which does NOT touch the paths...\" I think.\n\nAh, yes, I added include/scsi to the example to illustrate how\nmutiple paths worked and didn't update the later paragraph.\n\n>> * Alternate branch naming\n>>\n>> The original git scheme mixes tracking branches with all the other heads.\n>> This requires that you remember which branches are tracking branches and\n>> which aren't.  Hopefully, you remember what all your branches are for,\n>> but if you track a lot of remote repositories, you might not remember\n>> what every remote branch is for and what you called it locally.\n> \n> I think you wanted to mention .git/refs/remotes hierarchy and\n> separate-remote here, but haven't elaborated yet...\n\nYes, sorry.  I meant to research that and update this (I've never used\nit before), but I forgot.\n\n>> * Remote tags\n>>\n>> TODO: Figure out how remote tags work, under what circumstances\n>> they are fetched, and what git does if there are conflicts.\n> \n> refs/tags namespace is not policed at all by git and is treated\n> as a global namespace, controlled mostly by social convention\n> that your \"upstream\" (or central distribution point) supplies\n> tags for people who use it to synchronize to share.  Also, since\n> there is no guarantee that tags point at commits (v2.6.11-tree\n> tag is a pointer to a tree object, for example), there is no\n> farst-forward check performed for them.\n> \n> The rule we use to autofollow tags currently is:\n> \n> When you use shorthand fetch (or pull), we find tags that do not\n> exist locally, and if the object they point at are already found\n> in the repository then we fetch them automatically.  So for\n> example, if you are only tracking my 'maint' and not 'master'\n> nor 'next', and if you have tags up to v1.4.3.2, your \"git fetch\n> origin\" would update your copy of 'maint' and bring the commits\n> reachable from the tip of my 'maint'.  After that it notices\n> that v1.4.3.3, v1.4.3.4, v1.4.3.5 tags are in my repository but\n> missing from yours. It also notices that now you have\n> v1.4.3.3^{}, v1.4.3.4^{} and v1.4.3.5^{} in your repository, so\n> it issues another round of \"git fetch\" internally to fetch these\n> three tags.  At the same time it would also notice that I have\n> v1.4.4 tag that you do not have, but v1.4.4^0 commit is not\n> something you would get by fetching 'maint', so it would not\n> fetch it automatically.\n\nAh, okay.  Actually, v2.6.11-tree is a tag object\n(5dc01c595e6c6ec9ccda4f6f69c131c0dd945f8c) which points\nto a tree object (c39ae07f393806ccf406ef966e9a15afc43cc36a).\n\nI was wondering if git only shared refs/tags that pointed to\nheavyweight tag objects and not lightweight tags.\n\nThat appears to be the case:\n\nmkdir a b\ncd a\ngit-init-db\necho \"Hello, world\" > hello\ngit add hello\ngit commit -m \"Initial commit\"\ngit tag light\ngit tag -a -m \"Test tag\" heavy\ncd ../b\ngit-init-db\necho \"URL: ../a\" > .git/remotes/a\necho \"Pull: master:origin\" >> .git/remotes/a\ngit fetch a\n\nBut!  It only fetches tags if you specify a destination branch name.\nI hadn't noticed that before, but \"git-fetch <url> foo\" and\n\"git-fetch <url> foo:foo\" do different things on the receiver.\nDidn't they used to be synonyms?\n(I think it's a net gain in flexibility.)\n\nOh!  Also, the git-pull man page says that multiple branch names are\nallowed, even though the SYNOPSIS line says no.\n\nI also need to mention that if you want to pull a remote tag,\nyou need to prefix it with \"tags/\".  For some reason, the search\n"},{"id":"295624","messageId":"7v1wo22710.fsf@assigned-by-dhcp.cox.net","threadId":"43574","inReplyTo":"20061117011319.6738.qmail@science.horizon.com","subject":"Re: [DRAFT] Branching and merging with git","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2006-11-17T01:31:23Z","receivedAt":"2006-11-17T01:31:23Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"linux@horizon.com writes:\n\n> If anyone has any advice on how and why one would invoke git-merge\n> directly (the one why I know is to do a >2-way merge), that would\n> be appreciated.\n\nI use \"git pull . topicA topicB\" for a tetrapus, so that is not\na reason for me, but when a topicA's older parts are worthy to\nbe in 'next' while later parts are not yet, I often do (on 'next'):\n\n\n\tgit merge \"Merge early part of branch 'topicA'\" HEAD topicA~3\n\nAlso I used to do\n\n\tgit merge fast HEAD someTopicIknowIsAFastForward\n\nbecause it felt faster than \"git pull . someTopicIknowisAFastForward\"\nbut I do not do that these days and I would not recommend it to anybody.\n\n>>> 2) Revert changes to a small number of files.\n>>>\n>>> \tgit checkout [<revision>] [--] <paths>\n>>>    will copy the version of the <paths> from the index to the working\n>>>    directory.  If a <revision> is given, the index for those paths will\n>>>    be updated from the given revision before copying from the index to\n>>>    the working tree.\n>>>\n>>>    Unlike the version with no <paths> specified, this does NOT update\n>>>    HEAD, even if <paths> is \".\".\n>> \n>> It's great that you talk correctly about the latest feature-fix\n>> that is queued for maint but not yet pushed out.\n>\n> Um... there's a fix in there?  I thought that's how it always worked.\n\nI do not think naming a directory (say, \".\") to mean \"revert\neverything underneath this directory\" worked until the patch I\nsent out post 1.4.4 release.\n\n> I also need to mention that if you want to pull a remote tag,\n> you need to prefix it with \"tags/\".\n\nYes, recent -mm announce message says \"git pull ... tag v2.x-mmY\".\n\"tag v2.x-mmy\" is a shorthand for \"refs/tags/v2.x-mmY:refs/tags/v2.x-mmY\"\n\n"}]}