{"thread":{"id":"2704","subject":"git-name-rev off-by-one bug","startedAt":"2005-11-28T23:42:56Z","lastAt":"2005-12-09T01:45:20Z","messageCount":64,"participants":["linux@horizon.com","Junio C Hamano","Petr Baudis","Linus Torvalds","Daniel Barkalow","Randal L. Schwartz","Sven Verdoolaege","H. Peter Anvin","Alan Chandler","Josef Weidendorfer"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"12907","messageId":"20051128234256.1508.qmail@science.horizon.com","threadId":"2704","inReplyTo":null,"subject":"git-name-rev off-by-one bug","fromName":"","fromEmail":"linux@horizon.com","sentAt":"2005-11-28T23:42:56Z","receivedAt":"2005-11-28T23:42:56Z","isPatch":false,"sender":{"key":"linux@horizon.com","avatar":null},"body":"I've been trying to wrap my head around git for a while now, and finding\nthings a bit confusing.  Basically, the reason that I'm scared to trust\nit with my code is that all sharing is done via push and pull, and they\nare done by merging, and merging isn't described very well anywhere.\n\nThere's lots of intimate *detail* of merge algorithms (hiding in, of all\nplaces, the git-read-tree documentation, which is not the obvious place\nfor a beginner to look), but the important high-level questions like \"what\nhappens to all my hard work if there's a merge conflict?\" or \"what if I\nforget to git-update-index before doing the merge?\" are not really clear.\nI don't like to go ahead if I'm not confident I can get back.\n\n(Being able to back up the object database is obviously simple, but what\nhappens if the index holds HEAD+1, the working directory holds HEAD+2,\nand I try to mere the latest changes from origin?  Are either HEAD+1 or\nHEAD+2 in danger of being lost, or will checking them in later overwrite\nthe merge, or what?)\n\nAnyway, I'm doing some experiments and trying to understand it, and writing\nwhat I learn as I go, which will hopefully be useful to someone.\n\n\nAnother very confusing thing is the ref syntax with all those ~12^3^22^2\nsuffixes.  The git tutorial uses \"master^\" and \"master^2\" syntax, but\ndoesn't actually explain it.\n\nThe meaning can be found on the second page of the git-rev-parse manual.\nIf, that is, you think to read that man page, and if you don't stop\nreading after the first page tells you that it's a helper for scripts\nnot meant to be invoked directly by the end-user.\n\nTrying to see if I understood what was going on, I picked a random rev out of\ngit-show-branch output and tried git-name-rev:\n\n> $ git-name-rev 365a00a3f280f8697e4735e1ac5b42a1c50f7887\n> 365a00a3f280f8697e4735e1ac5b42a1c50f7887 maint~404^1~7\n\n(If you care, maint=93dcab2937624ebb97f91807576cddb242a55a46)\n\nAnd was very confused when git-rev-parse didn't invert the operation:\n\n> $ git-rev-parse maint~404^1~7\n> f69714c38c6f3296a4bfba0d057e0f1605373f49\n\nI spent a while verifying that I understood that ^1 == ^ == ~1, so\n~404^1~7 = ~412, and that gave the same unwanted result:\n\n> $ git-rev-parse maint~412\n> f69714c38c6f3296a4bfba0d057e0f1605373f49\n\nAfter confusing myself for a while, I looked to see why git-name-rev\nwould output such a redundant name and found that it was simply\nwrong.  Fixing the symbolic name worked:\n\n> $ git-rev-parse maint~404^2~7\n> 365a00a3f280f8697e4735e1ac5b42a1c50f7887\n\nYou can either go with a minimal fix:\ndiff --git a/name-rev.c b/name-rev.c\nindex 7d89401..f7fa18c 100644\n--- a/name-rev.c\n+++ b/name-rev.c\n@@ -61,9 +61,10 @@ copy_data:\n \n \t\t\tif (generation > 0)\n \t\t\t\tsprintf(new_name, \"%s~%d^%d\", tip_name,\n-\t\t\t\t\t\tgeneration, parent_number);\n+\t\t\t\t\t\tgeneration, parent_number+1);\n \t\t\telse\n-\t\t\t\tsprintf(new_name, \"%s^%d\", tip_name, parent_number);\n+\t\t\t\tsprintf(new_name, \"%s^%d\", tip_name,\n+\t\t\t\t\t\tparent_number+1);\n \n \t\t\tname_rev(parents->item, new_name,\n \t\t\t\tmerge_traversals + 1 , 0, 0);\n\n\nOr you can get a bit more ambitious and write ~1 as ^:\n\ndiff --git a/name-rev.c b/name-rev.c\nindex 7d89401..82053c8 100644\n--- a/name-rev.c\n+++ b/name-rev.c\n@@ -57,13 +57,17 @@ copy_data:\n \t\t\tparents;\n \t\t\tparents = parents->next, parent_number++) {\n \t\tif (parent_number > 0) {\n-\t\t\tchar *new_name = xmalloc(strlen(tip_name)+8);\n+\t\t\tunsigned const len = strlen(tip_name);\n+\t\t\tchar *new_name = xmalloc(len+8);\n \n-\t\t\tif (generation > 0)\n-\t\t\t\tsprintf(new_name, \"%s~%d^%d\", tip_name,\n-\t\t\t\t\t\tgeneration, parent_number);\n-\t\t\telse\n-\t\t\t\tsprintf(new_name, \"%s^%d\", tip_name, parent_number);\n+\t\t\tmemcpy(new_name, tip_name, len);\n+\n+\t\t\tif (generation == 1)\n+\t\t\t\tnew_name[len++] = '^';\n+\t\t\telse if (generation > 1)\n+\t\t\t\tlen += sprintf(new_name+len, \"~%d\", generation);\n+\n+\t\t\tsprintf(new_name+len, \"^%d\", parent_number+1);\n \n \t\t\tname_rev(parents->item, new_name,\n \t\t\t\tmerge_traversals + 1 , 0, 0);\n\n\nWhile I'm at it, I notice some unnecessary invocations of expr in some\nof the shell scripts.  You can do it far more simply using the ${var#pat}\nand ${var%pat} expansions to strip off leading and trailing patterns.\nFor example:\n\ndiff --git a/git-cherry.sh b/git-cherry.sh\nindex 867522b..c653a6a 100755\n--- a/git-cherry.sh\n+++ b/git-cherry.sh\n@@ -23,8 +23,7 @@ case \"$1\" in -v) verbose=t; shift ;; esa\n \n case \"$#,$1\" in\n 1,*..*)\n-    upstream=$(expr \"$1\" : '\\(.*\\)\\.\\.') ours=$(expr \"$1\" : '.*\\.\\.\\(.*\\)$')\n-    set x \"$upstream\" \"$ours\"\n+    set x \"${1%..*}\" \"${1#*..}\"\n     shift ;;\n esac\n \nThis works in dash and is in the POSIX spec.  It doesn't work in some\nvery old /bin/sh implementations (such as Solaris still ships), but I'm\npretty sure it was introduced at the same time as $(), and the scripts\nuse *that* all over the place.\n\n% sh\n$ uname -s -r\nSunOS 5.9\n$ foo=bar\n$ echo ${foo#b}\nbad substitution\n$ echo `echo $foo`\nbar\n$ echo $(echo $foo)\nsyntax error: `(' unexpected\n\nAnyway, if it's portable enough, it's faster.  Ah... I just found discussion\nof this in late September, but it's not clear what the resolution was.\nhttp://marc.theaimsgroup.com/?t=112746188000003\n\n\n(Oh, yes: all of the above patches are released into the public domain.\nCopyright abandoned.  Have fun.)\n"},{"id":"12909","messageId":"7vhd9wngn6.fsf@assigned-by-dhcp.cox.net","threadId":"2704","inReplyTo":"20051128234256.1508.qmail@science.horizon.com","subject":"Re: git-name-rev off-by-one bug","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2005-11-29T05:54:05Z","receivedAt":"2005-11-29T05:54:05Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"linux@horizon.com writes:\n\n> (Being able to back up the object database is obviously simple, but what\n> happens if the index holds HEAD+1, the working directory holds HEAD+2,\n> and I try to mere the latest changes from origin?  Are either HEAD+1 or\n> HEAD+2 in danger of being lost, or will checking them in later overwrite\n> the merge, or what?)\n\nThanks for the complaints.  No sarcasm intended.  Yours is\nexactly the kind of message we (people who've been around here\nfor too long) need to hear.\n\nAlthough the technical details are hidden in the documentation\nwhich needs reorganization to make them easier to find [*1*] as\nyou point out, the guiding principle for merge is quite simple.\n\nTo the git barebone Porcelain layer (things that start with\ngit-*, not with cg-*) [*2*], a merge is always between the\ncurrent HEAD and one or more remote branch heads, and the index\nfile must exactly match the tree of HEAD commit (i.e. the\ncontents of the last commit) when it happens.  In other words,\n\"git-diff --cached HEAD\" must report no changes [*3*].  So\nHEAD+1 must be HEAD in your above notation, or merge will refuse\nto do any harm to your repository (that is, it may fetch the\nobjects from remote, and it may even update the local branch\nused to keep track of the remote branch with \"git pull remote\nrbranch:lbranch\", but your working tree, .git/HEAD pointer and\nindex file are left intact).\n\nYou may have local modifications in the working tree files.  In\nother words, \"git-diff\" is allowed to report changes (the\ndifference between HEAD+2 and HEAD+1 in your notation).\nHowever, the merge uses your working tree as the working area,\nand in order to prevent the merge operation from losing such\nchanges, it makes sure that they do not interfere with the\nmerge. Those complex tables in read-tree documentation define\nwhat it means for a path to \"interfere with the merge\".  And if\nyour local modifications interfere with the merge, again, it\nstops before touching anything.\n\nSo in the above two \"failed merge\" case, you do not have to\nworry about lossage of data --- you simply were not ready to do\na merge, so no merge happened at all.  You may want to finish\nwhatever you were in the middle of doing, and retry the same\npull after you are done and ready.\n\nWhen things cleanly merge, these things happen:\n\n (1) the results are updated both in the index file and in your\n     working tree,\n (2) index file is written out as a tree,\n (3) the tree gets committed, and \n (4) the HEAD pointer gets advanced.\n\nBecause of (2), we require that the original state of the index\nfile to match exactly the current HEAD commit; otherwise we will\nwrite out your local changes already registered in your index\nfile (the difference between HEAD+1 and HEAD in your notation)\nalong with the merge result, which is not good.  Because (1)\ninvolves only the paths different between your branch and the\nremote branch you are pulling from during the merge (which is\ntypically a fraction of the whole tree), you can have local\nmodifications in your working tree as long as they do not\noverlap with what the merge updates.\n\nWhen there are conflicts, these things happen:\n\n (0) HEAD stays the same.\n\n (1) Cleanly merged paths are updated both in the index file and\n     in your working tree.\n\n (2) For conflicting paths, the index file records the version\n     from HEAD. The working tree files have the result of\n     \"merge\" program; i.e. 3-way merge result with familiar\n     conflict markers <<< === >>>.\n\n (3) No other changes are done.  In particular, the local\n     modifications you had before you started merge will stay the\n     same and the index entries for them stay as they were,\n     i.e. matching HEAD.\n\nAfter seeing a conflict, you can do two things:\n\n * Decide not to merge.  The only clean-up you need are to reset\n   the index file to the HEAD commit to reverse (1) and to clean\n   up working tree changes made by (1) and (2); \"git-reset\" can\n   be used for this.\n\n * Resolve the conflicts.  \"git-diff\" would report only the\n   conflicting paths because of the above (1) and (2).  Edit the\n   working tree files into a desirable shape, git-update-index\n   them, to make the index file contain what the merge result\n   should be, and run \"git-commit\" to commit the result.\n\n\n[Footnotes]\n\n*1* It is a shame that the most comprehensive definition of\n3-way read-tree semantics is in t/t1000-read-tree-m-3way.sh test\nscript.\n\n*2* Cogito (things that start with cg-*) seems to try to be\ncleverer.  Pasky might want to brag about the rules in Cogito\nland.\n\n*3* This is a bit of lie.  In certain special cases, your index\nare allowed to be different from the tree of HEAD commit;\nbasically your index entries are allowed to match the result of\ntrivial merge already (e.g. you received the same patch from\nexternal source to produce the same result as what you are\nmerging).  For example, if a path did not exist in the common\nancestor and your head commit but exists in the tree you are\nmerging into your repository, and if you already happen to have\nthat path exactly in your index, the merge does not have to\nfail.  This is case #2 in the 3-way read-tree table in t/t1000.\n"},{"id":"12921","messageId":"20051129080529.20705.qmail@science.horizon.com","threadId":"2704","inReplyTo":"7vhd9wngn6.fsf@assigned-by-dhcp.cox.net","subject":"Re: git-name-rev off-by-one bug","fromName":"","fromEmail":"linux@horizon.com","sentAt":"2005-11-29T08:05:29Z","receivedAt":"2005-11-29T08:05:29Z","isPatch":false,"sender":{"key":"linux@horizon.com","avatar":null},"body":"> Thanks for the complaints.  No sarcasm intended.  Yours is\n> exactly the kind of message we (people who've been around here\n> for too long) need to hear.\n\nThanks for taking it so well!  I'm trying to really *understand* git,\nso I can predict its behaviour, but I've been coming to the conclusion\nthat the only way to do that is by re-reading the mailing list from day 1.\n\nAnd to understand git at all, you have to understand merging, since\ndoing merging fast and well is the central reason for git's entire\nexistence.  Single-developer porcelain like \"cvs annotate\" is\nnoticeably lacking, but branching and merging is great.\n\n(In particular, and unlike other SCMs, \"push\" and \"pull\" are\nbased on merging!  So I can't even understand what pulling from\nLinus's tree does until I understand merging.)\n\n\nI'm working on some notes to explain git to myself and people\nI work with, which I'll post when they're vaguely complete.\n\n> To the git barebone Porcelain layer (things that start with\n> git-*, not with cg-*) [*2*], a merge is always between the\n> current HEAD and one or more remote branch heads, and the index\n> file must exactly match the tree of HEAD commit (i.e. the\n> contents of the last commit) when it happens.  In other words,\n> \"git-diff --cached HEAD\" must report no changes [*3*].  So\n> HEAD+1 must be HEAD in your above notation, or merge will refuse\n> to do any harm to your repository (that is, it may fetch the\n> objects from remote, and it may even update the local branch\n> used to keep track of the remote branch with \"git pull remote\n> rbranch:lbranch\", but your working tree, .git/HEAD pointer and\n> index file are left intact).\n\nRight!  Since the object database is strictly append-only, it's easy to\nsee how such changes are quite harmless, and updating a tracking branch\nis hardly a big nasty surprise.\n\nIt's the index and working directory that are volatile, and that I was\nworried about.\n\nBUT... what's the second argument to git-read-tree for, if it\nalways has to be HEAD?\n\nBTW, I'd change the description of git-read-tree from\n\n>     Reads the tree information  given  by  <tree-ish>  into  the directory\n>     cache, but does not actually update any of the files it \"caches\". (see:\n>     git-checkout-index)\n\nto\n\n      Reads the tree information given by <tree-ish> into the index.\n      The working directory is not modified in any way (unless -u\n      is used).  Use git-checkout-index to do that.\n\n      In addition to the simple one-tree case, this can (with the\n      -m flag) merge 2 or 3 trees into the index.  When used with\n      -m, the -u flag causes it to also update the files in the\n      working directory.\n\n      Trivial merges are done by \"git-read-tree\" itself.  Conflicts\n      are left in an unmerged state for git-merge-index to resolve.\n\n> You may have local modifications in the working tree files.  In\n> other words, \"git-diff\" is allowed to report changes (the\n> difference between HEAD+2 and HEAD+1 in your notation).\n> However, the merge uses your working tree as the working area,\n> and in order to prevent the merge operation from losing such\n> changes, it makes sure that they do not interfere with the\n> merge.  Those complex tables in read-tree documentation define\n> what it means for a path to \"interfere with the merge\".  And if\n> your local modifications interfere with the merge, again, it\n> stops before touching anything.\n\nTHANK YOU for finally making this clear!  I was wondering why the\nhell a 2-way merge looked more complex than a 3-way.  (Although,\nadmittedly, I'm *still* not clear on what the difference is.  It\nseems like a 2-way just picks the origin commit automatically.)\nSo it goes like this:\n\n- git-merge will refuse to do anything if there are any uncommitted changes\n  in the index.  [footnote about harmless exceptions]\n- git-merge will refuse to do anything if there are changes in the\n  working directory to a file that would be affected by the merge.\n  You CAN, however, have unindexed changes to files that are unchanged\n  by the merge.\n\n\nThe description of a 1-way merge in git-read tree is quite confusing.\nHere's a rephrasing; do I understand it?\n\nREADING\n\n    Without -m, git-read-tree pulls a specified tree into the index.\n    Any file whose underlying blob is changed by the update will have\n    its cached stat data invalidated, so it will appear in the output\n    of git-diff-files, and git-checkout-index -f will overwrite it.\n\n    A single-tree merge is a slightly nicer variant on this.\n\nMERGING\n    ...\n\n\nSingle Tree Merge\n    If only one tree is specfied, any file whose blob changes as a\n    result of the update is compared with the working directory file,\n    and the cached stat data updated if the working directory file\n    matches the new blob.  Thus, working directory files which happen to\n    match the contents of the new tree will be excluded from the outout\n    of git-diff-files, and git-checkout-index -f will not update their\n    file modification times.\n\n    This is basically the effect of git-update-index --refresh.\n\n    This is actually usually preferable to the non-merge case, but\n    does do extra work.\n\nI haven't found the code yet, but obviously if the working directory\nfile is clean relative to the previous blob, it's dirty relative to\nthe changed blob, so there's no need to actually read the file.\n\nUm... I just tried it, and it appears that things do NOT work as\nI just described.  Time to read the code...\n\n\nBTW, an even cuter way of writing same() in read_tree.c would be:\n\nstatic int same(struct cache_entry *a, struct cache_entry *b)\n{\n\tif (!a || !b)\n\t\treturn a == b;\n        return a->ce_mode == b->ce_mode &&\n                !memcmp(a->sha1, b->sha1, 20);\n}\n\n(I presume that\nreturn a&&b ? a->ce_mode == b->ce_mode && !memcmp(a->sha1, b->sha1, 20) : a==b;\nwould be taking it too far...)\n\nOh, and the git-read-tree man page fails to mention --reset and --trivial.\nAnd the usage message should have <sha> changed to <tree>.\n\n> So in the above two \"failed merge\" case, you do not have to\n> worry about lossage of data --- you simply were not ready to do\n> a merge, so no merge happened at all.  You may want to finish\n> whatever you were in the middle of doing, and retry the same\n> pull after you are done and ready.\n\nI feel about a thousand percent better about git already.\n\n> When things cleanly merge, these things happen:\n>\n> (1) the results are updated both in the index file and in your\n>     working tree,\n> (2) index file is written out as a tree,\n> (3) the tree gets committed, and \n> (4) the HEAD pointer gets advanced.\n\nThis is git-merge, as opposed to the more primitive git-read-tree -m\nplus git-merge-index, right?\n\n(Aside, you should document that got-merge --no-commit saves the <msg>\nin .git/MERGE_MSG, and git-commit uses it as the default message.\nOtherwise, users wonder why the hell it asks for a commit message it\nknows won't be used.)\n\n> Because of (2), we require that the original state of the index\n> file to match exactly the current HEAD commit; otherwise we will\n> write out your local changes already registered in your index\n> file (the difference between HEAD+1 and HEAD in your notation)\n> along with the merge result, which is not good.\n\n> *3* This is a bit of lie.  In certain special cases, your index\n> are allowed to be different from the tree of HEAD commit;\n> basically your index entries are allowed to match the result of\n> trivial merge already (e.g. you received the same patch from\n> external source to produce the same result as what you are\n> merging).  For example, if a path did not exist in the common\n> ancestor and your head commit but exists in the tree you are\n> merging into your repository, and if you already happen to have\n> that path exactly in your index, the merge does not have to\n> fail.  This is case #2 in the 3-way read-tree table in t/t1000.\n\nAh, yes, the light dawns!  So it *is* okay if you have an uncommitted\nchange in the index which exactly matches what git-read-tree -m would\nhave done anyway.  It doesn't make a difference to the final state\nof the index, and forcing the poor user to undo it just so the merge\ncan redo it is simply annoying.\n\nBut it's NOT okay if you have any other change in the index, even in a\nfile unaffected by the merge, because then the final state would not\nbe the result of the merge, and that could be confusing.\n\n> Because (1)\n> involves only the paths different between your branch and the\n> remote branch you are pulling from during the merge (which is\n> typically a fraction of the whole tree), you can have local\n> modifications in your working tree as long as they do not\n> overlap with what the merge updates.\n\nWonderfully clear.  Such changes must not exist at the git-read-tree\nlevel, since there's not even a way to represent them to\ngit-merge-index.  Still, this can save considerable bother when\ntrying to track someone else's tree.\n\n> When there are conflicts, these things happen:\n>\n>  (0) HEAD stays the same.\n>\n>  (1) Cleanly merged paths are updated both in the index file and\n>      in your working tree.\n> \n>  (2) For conflicting paths, the index file records the version\n>      from HEAD. The working tree files have the result of\n>      \"merge\" program; i.e. 3-way merge result with familiar\n>      conflict markers <<< === >>>.\n> \n>  (3) No other changes are done.  In particular, the local\n>      modifications you had before you started merge will stay the\n>      same and the index entries for them stay as they were,\n>      i.e. matching HEAD.\n\nSo this is a lot like what CVS does, but neater because all the\nmerge sources are available unmodified in the index.  Excellent.\n\n> After seeing a conflict, you can do two things:\n>\n> * Decide not to merge.  The only clean-up you need are to reset\n>   the index file to the HEAD commit to reverse (1) and to clean\n>   up working tree changes made by (1) and (2); \"git-reset\" can\n>   be used for this.\n\nCool.  Two minor questions:\n\n- Doesn't any non-trivial merge or invocation of git-update-index\n  produce blob objects in the database that become garbage if you\n  do this?  Or are they somehow kept separate until a tree object\n  is created to point to them?\n\n  (You could have an \"unreferenced\" bit in the index, indicating that\n  the blobs in question could be found in .git/pending rather than\n  .git/objects, until git-write-tree moved them into the database.\n  But I don't see mention of any such scheme.)\n\n- Is there any difference between \"git-reset --hard\" and \"git-checkout -f\"?\n\n> * Resolve the conflicts.  \"git-diff\" would report only the\n>   conflicting paths because of the above (1) and (2).  Edit the\n>   working tree files into a desirable shape, git-update-index\n>   them, to make the index file contain what the merge result\n>   should be, and run \"git-commit\" to commit the result.\n\nOkay, so git-update-index will overwrite a staged file with a\nfresh stage-0 copy.  And git-commit will refuse to commit\n(to be precise, it'll stop at the git-write-tree stage) if there\nare unresolved conflicts.\n\nIf you want to see the unmodified input files, you can find their\nIDs with \"git-ls-files -u\" and then get a copy with \"git-cat-file blob\"\nor \"git-unpack-file\".  git-merge-index is basically a different way to\nprocess the output of git-ls-files -u.\n\n\n> *1* It is a shame that the most comprehensive definition of\n> 3-way read-tree semantics is in t/t1000-read-tree-m-3way.sh test\n> script.\n\nThanks for the pointer; I'll go and read it!\n\n> *2* Cogito (things that start with cg-*) seems to try to be\n> cleverer.  Pasky might want to brag about the rules in Cogito\n> land.\n\nIn fact, he might want to explain what the difference is between cogito\nand git.  Most particularly, are there any restrictions on mixing cg-*\nand git-* operations from within the same directory?\n\nI've been assuming that cogito is just series of friendlier\nutilities, in much the same way that a text editor is friendlier\nthan \"cat > kernel/sched.c\", so I'll study it after I understand\ncore git.\n\n\nOne more question to be sure I understand merging... AFAICT, it would\nbe theoretically possible to stop distinguishing \"stage 2\" and \"stage 0\".\nIf there is only a stage 2 file, then in-index will immediately\ncollapse it to stage 0, and if there are any other stage files,\nyou know there's an incomplete merge.\n\n(Alternatively, you could collapse \"stage 3\" and \"stage 0\", since\nstages 2 and 3 are treated identically, but traditionally, stage 2 is\nthe \"trunk\" and state 3 is the \"branch\" being merged in.)\n"},{"id":"12925","messageId":"7voe43iyyu.fsf@assigned-by-dhcp.cox.net","threadId":"2704","inReplyTo":"20051129080529.20705.qmail@science.horizon.com","subject":"Re: git-name-rev off-by-one bug","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2005-11-29T09:29:29Z","receivedAt":"2005-11-29T09:29:29Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"linux@horizon.com writes:\n\n> (In particular, and unlike other SCMs, \"push\" and \"pull\" are\n> based on merging!  So I can't even understand what pulling from\n> Linus's tree does until I understand merging.)\n\nIf you do \"git pull git://.../linux-2.6/\", it fetches the\nobjects and stores Linus \"master\" into .git/FETCH_HEAD, and then\nmerges that into whatever branch you happen to be on (but you\nalready know that).\n\n> BUT... what's the second argument to git-read-tree for, if it\n> always has to be HEAD?\n\ngit-read-tree is purely \"a building block to be scripted\" in\nyour second mail (private?).  In my message you are replying to,\nI outlined what the end-user level tool, git-pull (and git-merge\nit uses) does, which is built using git-read-tree, and we happen\nto always pass HEAD as its second argument.  But it does not\nhave to be that way.  One thing planned in the future is to do a\nmerge in a temporary working directory, not in your primary\nworking tree, and when we implement that, the second argument\nwill be whatever branch head you are pulling into, not\nnecessarily your current HEAD.\n\n> BTW, I'd change the description of git-read-tree from\n\nThanks.  I am a bit too tired tonight so I may send you a\ncorrection later if what I am going to comment here turns out to\nbe incorrect, but a quick glance tells me this is a good\nclarification.\n\n> ...  I was wondering why the\n> hell a 2-way merge looked more complex than a 3-way.\n\n2-way is called merge but it is not about the merge at all\n(git-merge is mostly about 3-way merge).  It is more about\ncheckout.  Suppose you have checked out branch A, and have local\nmodificiations (both in index and in working tree).  You would\nwant to switch to branch B by \"git checkout B\" (without -f).\n2-way \"read-tree -m -u\" is used to ensure that you take your\nlocal modifications with you while checking out branch B into\nyour working tree, meaning:\n\n (1) local changes already registered in the index stays in the\n     index file; obviously this can be done only if A and B are\n     the same at such paths.\n\n (2) local changes not registered in the index stays in the\n     working tree; similar restriction applies but the rules are\n     more involved.\n\nSimilar to 3-way case, 2-way will refuse to lose your local\nmodifications, and that is the 2-way case table in\nDocumentation/git-read-tree.txt is about.\n\n> This is git-merge, as opposed to the more primitive git-read-tree -m\n> plus git-merge-index, right?\n\nEverything I wrote in the previous message was about the\nend-user tools git-pull/git-merge. \n\n> - Doesn't any non-trivial merge or invocation of git-update-index\n>   produce blob objects in the database that become garbage if you\n>   do this?\n\nWe produce garbage blobs all the time, and we do not care.  Even\nthe following sequence that does not involve any merge produces\na garbage blob for the first version of A that was faulty:\n\n        $ git checkout\n        $ edit A\n        $ git update-index A\n        $ make ;# oops, there is a mistake.\n        $ edit A\n        $ make ;# this time it is good.\n        $ git commit -a -m 'Finally compiles.'\n\nOccasional fsck-objects, prune and repack are your friends.\n\n> - Is there any difference between \"git-reset --hard\" and \"git-checkout -f\"?\n\n\"reset --hard\" does more thorough job removing unwanted files\nfrom your working tree.  It looks at your current HEAD, the\ncommit you are resetting to (when you say \"reset --hard\n<commit>\"), and your index file, and paths mentioned by any of\nthese three that should not remain (that is, not in the commit\nyou are resetting to) are removed from your working tree.  In\naddition, \"reset --hard <commit>\" updates the branch head and\ncan be used to rewind it.  On the other hand, \"checkout -f\"\ntells git to *ignore* what is in the index, so any file in the\nworking tree that used to be in the index (or old branch you\nwere working on) that does not exist in the branch you are\nchecking out is not removed.\n\nOn a related topic of removing unwanted paths, earlier I said\n2-way is used to make sure \"git checkout\" takes your changes\nwith you when you switch branches.  As a natural consequence of\nthis, if you do not have any local changes, \"git checkout\"\nwithout \"-f\" does the right thing -- it removes unwanted paths\nthat existed in the original branch but not in the branch you\nare switching to.\n\n> Okay, so git-update-index will overwrite a staged file with a\n> fresh stage-0 copy.  And git-commit will refuse to commit\n> (to be precise, it'll stop at the git-write-tree stage) if there\n> are unresolved conflicts.\n\nSorry, I was unclear that I was talking about end-user level\ntool.  The update-index here is not about the conflict\nresolution in the index file read-tree documentation talks\nabout.  That has already been done when \"merge\" ran in the\nconflicting case.  In the conflicting case, the working tree\nholds 3-way merge conflicting result, and the index holds HEAD\nversion at stage0 for such a path.  Hand resolving after\nupdate-index is to record what you eventually want to commit\n(i.e. you are not replacing higher stage entry in the index with\nstage0 entry -- you are replacing stage0 entry with another).\n\n> If you want to see the unmodified input files, you can find their\n> IDs with \"git-ls-files -u\" and then get a copy with \"git-cat-file blob\"\n> or \"git-unpack-file\".  git-merge-index is basically a different way to\n> process the output of git-ls-files -u.\n\nYes, in principle.  But in practice you usually do not use these\nlow level tools yourself.  When git-merge returns with\nconflicting paths, most of them have already been collapsed into\nstage0 and git-ls-files --unmerged would not show.  The only\ncase I know of that you may still see higher stage entries in\nthe index these days is merging paths with different mode bits.\nWe used to leave higher stage entries when both sides added new\nfile at the same path, but even that we show as merge from\ncommon these days.\n"},{"id":"12927","messageId":"20051129103157.GW22159@pasky.or.cz","threadId":"2704","inReplyTo":"20051129080529.20705.qmail@science.horizon.com","subject":"Re: git-name-rev off-by-one bug","fromName":"Petr Baudis","fromEmail":"pasky@suse.cz","sentAt":"2005-11-29T10:31:57Z","receivedAt":"2005-11-29T10:31:57Z","isPatch":false,"sender":{"key":"pasky@ucw.cz","avatar":"https://avatars.githubusercontent.com/u/18439?v=4"},"body":"Dear diary, on Tue, Nov 29, 2005 at 09:05:29AM CET, I got a letter\nwhere linux@horizon.com said that...\n> > *2* Cogito (things that start with cg-*) seems to try to be\n> > cleverer.  Pasky might want to brag about the rules in Cogito\n> > land.\n\n> In fact, he might want to explain what the difference is between cogito\n> and git.  Most particularly, are there any restrictions on mixing cg-*\n> and git-* operations from within the same directory?\n\n  Nope, except:\n\nCogito vs. other GIT tools\n~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nYou can *MOSTLY* use Cogito in parallel with other GIT frontends (e.g.\nStGIT), as well as the GIT plumbing and core GIT tools - the tools only\nneed to keep HEAD in place and follow the standardized `refs/`\nhierarchy. The only notable exception is that you should stick with a\nsingle toolkit during a merge.\n\n\t(-- Cogito README)\n\n  So exactly during a merge, things might not blend well, since Cogito\ndoes things a bit differently. It knows of no MERGE_HEAD, MERGE_MSG and\nsuch, and instead passes stuff over different channels or computes/asks\nit at different times. Historically, cg-merge and git-merge evolution\nhas been almost entirely separate.\n\n\n  From the user POV, the main difference between Cogito and GIT merging\nis that:\n\n  (i) Cogito tries to never leave the index \"dirty\" (i.e. containing\nunmerged entries), and instead all conflicts should propagate to the\nworking tree, so that the user can resolve them without any further\nspecial tools. (What is lacking here is that Cogito won't proofcheck\nthat you really resolved them all during a commit. That's a big TODO.\nBut core GIT won't you warn about committing the classical << >> ==\nconflicts either.)\n\n  (ii) Cogito will handle trees with some local modifications better -\nbasically any local modifications git-read-tree -m won't care about.\nI didn't read the whole conversation, so to reiterate: git-read-tree\nwill complain when the index does not match the HEAD, but won't\ncomplain about modified files in the working tree if the merge is not\ngoing to touch them. Now, let's say you do this (output is visually\nonly roughly or not at all resembling what would real tools tell you):\n\n\t$ ls\n\ta b c\n\t$ echo 'somelocalhack' >>a\n\t$ git merge \"blah\" HEAD remotehead\n\tFile-level merge of 'b' and 'c'...\n\tOops, 'b' contained local conflicts.\n\tAutomatic merge aborted, fix up by hand.\n\t$ fixup b\n\t$ git commit\n\tCommitted files 'a', 'b', 'c'.\n\nOops. It grabbed your local hack and committed it along the merge.\nCogito won't do this, it will hold 'a' back when doing the merge commit\n(if it works right; in the past, there were several bugs related to\nthis, but hopefully they are all fixed by now):\n\n\t$ ls\n\ta b c\n\t$ echo 'somelocalhack' >>a\n\t$ cg-merge remotehead\n\t... Merging c\n\t... Merging b\n\tConflicts during merge of 'b'.\n\n\t\tFix up the conflicts, then kindly do cg-commit.\n\t$ fixup b\n\t$ cg-commit -m\"blah\"\n\tCommitted files 'b', 'c'.\n\nAlso note that the cg-merge usage is simpler and you give the \"blah\"\nmessage only to cg-commit, when it's for sure you are going to use it.\n\n  (iii) Cogito does not support the smart recursive merging strategy.\nThat means it won't follow renames, and in case of multiple merge bases,\nit will not merge them recursively, but it will just ask you to choose\none manually, or suggest you the most conservative merge base (where you\nshould get no false clean merges, but you will probably have to deal\nwith a lot of conflicts).\n\n-- \n\t\t\t\tPetr \"Pasky\" Baudis\nStuff: http://pasky.or.cz/\nVI has two modes: the one in which it beeps and the one in which\nit doesn't.\n"},{"id":"12941","messageId":"7vhd9vgumb.fsf@assigned-by-dhcp.cox.net","threadId":"2704","inReplyTo":"20051129103157.GW22159@pasky.or.cz","subject":"Re: git-name-rev off-by-one bug","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2005-11-29T18:46:20Z","receivedAt":"2005-11-29T18:46:20Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Petr Baudis <pasky@suse.cz> writes:\n\n>   (ii) Cogito will handle trees with some local modifications better -\n> basically any local modifications git-read-tree -m won't care about.\n> I didn't read the whole conversation, so to reiterate: git-read-tree\n> will complain when the index does not match the HEAD, but won't\n> complain about modified files in the working tree if the merge is not\n> going to touch them. Now, let's say you do this (output is visually\n> only roughly or not at all resembling what would real tools tell you):\n>\n> \t$ ls\n> \ta b c\n> \t$ echo 'somelocalhack' >>a\n> \t$ git merge \"blah\" HEAD remotehead\n> \tFile-level merge of 'b' and 'c'...\n> \tOops, 'b' contained local conflicts.\n> \tAutomatic merge aborted, fix up by hand.\n> \t$ fixup b\n> \t$ git commit\n> \tCommitted files 'a', 'b', 'c'.\n>\n> Oops. It grabbed your local hack and committed it along the merge.\n\nAre you sure about this?\n\nIn the above sequence, after you touch a with 'somelocalhack',\nthere is no 'git update-index a', until you say 'git commit'\nthere, so I do not think that mixup is possible.\n\nThe \"fixup b\" step is actually two commands, so after merge\ncommand, you would do:\n\n        $ edit b\n\t$ git update-index b ;# mark that you are dealt with it\n\t$ git commit ;# commits what is in index\n\nAfter the above steps, \"git diff\" (that is working tree against\nindex) still reports your local change to \"a\", which were _not_\ncommitted.\n\nMaybe you were mistaken because Cogito tries to be nice to its\nusers and always does a moral equivalent of \"git commit -a\"\n(unless the user tells you to commit only specific paths), but\nyou needed to special case merge resolution commit to make sure\nthat you exclude \"a\" in the above example?  \"git commit\" does\nnot do \"-a\" by default, and it will stay that way, so I do not\nthink we do not have the \"Oops\" you described above.\n\n\"Oops\" would happen only if you did \"git commit -a\" instead at\nthe last step.\n"},{"id":"12946","messageId":"20051129214055.8689.qmail@science.horizon.com","threadId":"2704","inReplyTo":"20051129103157.GW22159@pasky.or.cz","subject":"Re: git-name-rev off-by-one bug","fromName":"","fromEmail":"linux@horizon.com","sentAt":"2005-11-29T21:40:55Z","receivedAt":"2005-11-29T21:40:55Z","isPatch":false,"sender":{"key":"linux@horizon.com","avatar":null},"body":"I'm feeling slightly guilty about eliciting such a flood of help, but I'm\ncertainly leraning a lot.  But there's one statement that, while I'm not\ndoubting it's accuracy, seems at odds with the mental model I'm building.\nI must be misunderstanding something.\n\njunkio wrote:\n>> Okay, so git-update-index will overwrite a staged file with a\n>> fresh stage-0 copy.  And git-commit will refuse to commit\n>> (to be precise, it'll stop at the git-write-tree stage) if there\n>> are unresolved conflicts.\n>\n> Sorry, I was unclear that I was talking about end-user level\n> tool.  The update-index here is not about the conflict\n> resolution in the index file read-tree documentation talks\n> about.  That has already been done when \"merge\" ran in the\n> conflicting case.  In the conflicting case, the working tree\n> holds 3-way merge conflicting result, and the index holds HEAD\n> version at stage0 for such a path.  Hand resolving after\n> update-index is to record what you eventually want to commit\n> (i.e. you are not replacing higher stage entry in the index with\n> stage0 entry -- you are replacing stage0 entry with another).\n> \n>> If you want to see the unmodified input files, you can find their\n>> IDs with \"git-ls-files -u\" and then get a copy with \"git-cat-file blob\"\n>> or \"git-unpack-file\".  git-merge-index is basically a different way to\n>> process the output of git-ls-files -u.\n>\n> Yes, in principle.  But in practice you usually do not use these\n> low level tools yourself.  When git-merge returns with\n> conflicting paths, most of them have already been collapsed into\n> stage0 and git-ls-files --unmerged would not show.  The only\n> case I know of that you may still see higher stage entries in\n> the index these days is merging paths with different mode bits.\n> We used to leave higher stage entries when both sides added new\n> file at the same path, but even that we show as merge from\n> common these days.\n\nAnd pasky reiterated:\n>   From the user POV, the main difference between Cogito and GIT merging\n> is that:\n>\n>  (i) Cogito tries to never leave the index \"dirty\" (i.e. containing\n> unmerged entries), and instead all conflicts should propagate to the\n> working tree, so that the user can resolve them without any further\n> special tools. (What is lacking here is that Cogito won't proofcheck\n> that you really resolved them all during a commit. That's a big TODO.\n> But core GIT won't you warn about committing the classical << >> ==\n> conflicts either.)\n\nThis seems odd to me.  There's an alternate implementation that\nI described that makes a lot more sense to me, based on my current\nstate of knowledge.  Can someone explain why my idea is silly?\n\n\nI'd imagine you'd consider user editing to be a last-resort merge\nalgorithm, but treat it like the other merges, and leave the file\nstaged while it's in progress.\n\nEither git-checkout-index or something similar would \"check out\"\nthe staged file with CVS-style merge markers.  And an eventual\ngit-update-index would replace the staged file with a stage-0,\njust like git-merge-one-file does automatically.\n\n\"git-diff\" could default to diffing against the stage-2 file to\nproduce the same reults as now, but you could also have an\noption to diff against a different stage, which might be useful.\n\n(This is another reason for my earlier comment that I don't think\nthe distinction between stage-0 and stage-2 is actually necessary.)\n\nAnd git-write-tree would naturally stop you from committing with\nunresolved conflicts.  You could still commit the conflict\nmarkers, but it would be a two-step process.\n\nYou'd have the simple principle that all merges start with git-read-tree\nproducing a staged file, and end with git-update-index collapsing\nthem when it's been resolved.  (Or something like git-reset throwing\neverything away.)\n\n\nHaving said all this, there's presumably a good reason why this is a\nbad idea.  Could someone enlighten me?\n\nThanks!\n"},{"id":"12959","messageId":"7vsltf6o8f.fsf@assigned-by-dhcp.cox.net","threadId":"2704","inReplyTo":"20051129214055.8689.qmail@science.horizon.com","subject":"Re: git-name-rev off-by-one bug","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2005-11-29T23:14:24Z","receivedAt":"2005-11-29T23:14:24Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"linux@horizon.com writes:\n\n> This seems odd to me.  There's an alternate implementation that\n> I described that makes a lot more sense to me, based on my current\n> state of knowledge.  Can someone explain why my idea is silly?\n\nIt is not silly.  Actually we have \"been there, done that\".\n\nWe used to leave the higher stages around in the index after\nautomerge failure.  Note that you would not just have stage2 in\nsuch a case.  stage1 keeps the common ancestor, stage2 has what\nyou started with, and stage3 holds the version from other\nbranch.  diff-stages can be used to diff between these stages.\nWe _could_ have added feature to either diff-stages or\ndiff-files to compare between stageN and working tree.\n\nHowever, this turned out to be not so convenient as we wished\ninitially.  What you would do after inspecting diffs between\nstage1 and stage3, between stage2 and stage3 and between stage1\nand stage2 typically ends up doing what \"merge\" have tried (and\nfailed) manually anyway, and being able to find the conflict\nmarkers by simply running \"git diff\" was just as good, except\nthat we risk getting still-unresolved files checked in if the\nuser is not careful.\n\nIf you want to be clever about an automated merge, you could\nwrite a new merge strategy to take the three trees and produce a\nbetter automerge result.  That is what Fredrik has done in his\ngit-merge-recursive (now default).  Or you could \"improve\"\ngit-merge-one-file to take three blob object names and leave\nfile~1 file~2 file~3 in the working tree, instead of (or in\naddition to) leaving a \"merge\" result with conflict markers, to\ngive the user ready access to the version from each stage.\n"},{"id":"12964","messageId":"20051130001503.28498.qmail@science.horizon.com","threadId":"2704","inReplyTo":"7vsltf6o8f.fsf@assigned-by-dhcp.cox.net","subject":"Re: git-name-rev off-by-one bug","fromName":"","fromEmail":"linux@horizon.com","sentAt":"2005-11-30T00:15:03Z","receivedAt":"2005-11-30T00:15:03Z","isPatch":false,"sender":{"key":"linux@horizon.com","avatar":null},"body":"> It is not silly.  Actually we have \"been there, done that\".\n\nUm, okay, but I don't see why you changed...\n\n> We used to leave the higher stages around in the index after\n> automerge failure.  Note that you would not just have stage2 in\n> such a case.  stage1 keeps the common ancestor, stage2 has what\n> you started with, and stage3 holds the version from other\n> branch.  diff-stages can be used to diff between these stages.\n> We _could_ have added feature to either diff-stages or\n> diff-files to compare between stageN and working tree.\n\nYes, exactly.  This is what I expected.\n\n> However, this turned out to be not so convenient as we wished\n> initially.  What you would do after inspecting diffs between\n> stage1 and stage3, between stage2 and stage3 and between stage1\n> and stage2 typically ends up doing what \"merge\" have tried (and\n> failed) manually anyway, and being able to find the conflict\n> markers by simply running \"git diff\" was just as good, except\n> that we risk getting still-unresolved files checked in if the\n> user is not careful.\n\nYou seem to be saying that producing a merge with conflict markers is\nwhat you (almost) always want, so it's the default.  No objections.\n\nBut why collapse the index and only keep stage2?  Why not leave all\nstages in the index *and* the merge-with-conflict-markers in the working\ndirectory?\n\nThey you could, for example, try alternate single-file merge algorithms\non the conflict, or regenerate the conflict markers if you wanted.\nBy keeping all of the source material around until the user has decided\non a resolution, you achieve maximal flexibility.\n\nThis is no more effort for the user to use in the common case (edit the\nconflicts and git-update-index), but lets you try various things in the\nworking directory and eaily back out of them.  (\"git-merge-index -s manual\n-a\" would regenerate all of the conflict markers.)  And it prevents a\ncheckin until the matter has been resolved.\n\n\nI'm wondering if this isn't a philosophical issue.  One side says that,\nsince all automated merging is complete, the stages should be collapsed.\nTo me, it makes more sense to leave out the adjective \"automated\" and\nconsider the merge to be incomplete; we're just putting the user in the\nloop when software fails.\n"},{"id":"12966","messageId":"7v4q5v5536.fsf@assigned-by-dhcp.cox.net","threadId":"2704","inReplyTo":"20051130001503.28498.qmail@science.horizon.com","subject":"Re: git-name-rev off-by-one bug","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2005-11-30T00:53:17Z","receivedAt":"2005-11-30T00:53:17Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"linux@horizon.com writes:\n\n> I'm wondering if this isn't a philosophical issue.\n\nI do not think so.  I have to admit I did not exactly agree with\nthe current behaviour when it was changed from the previous one,\nbut at the same time I did not have anything concrete against\nit, and I did not care too much about the details back then.  I\nsuspect it was primarily be done to make things easier for the\nend user without changing already existing tools (i.e.,\ngit-diff-files did not have to start taking --stage=2 flag to\ntell it to compare stage2 and working tree).\n\nThis is the message from Linus that announced the current\nbehaviour:\n\n\thttp://marc.theaimsgroup.com/?l=git&m=111826424425624\n"},{"id":"12967","messageId":"7vr78z3oy2.fsf@assigned-by-dhcp.cox.net","threadId":"2704","inReplyTo":"7v4q5v5536.fsf@assigned-by-dhcp.cox.net","subject":"Re: git-name-rev off-by-one bug","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2005-11-30T01:27:17Z","receivedAt":"2005-11-30T01:27:17Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Junio C Hamano <junkio@cox.net> writes:\n\n> linux@horizon.com writes:\n>\n>> I'm wondering if this isn't a philosophical issue.\n>\n> I do not think so....\n> ...\n> This is the message from Linus that announced the current\n> behaviour:\n>\n> \thttp://marc.theaimsgroup.com/?l=git&m=111826424425624\n\nReplying to myself.  In the message, Linus talks about being\nable to do (diff-cache is an old name for diff-index):\n\n\tgit-diff-files -p xyzzy ;# to compare with our version\n        git-diff-cache -p MERGE_HEAD xyzzy ;# to compare with his\n\nBut because of the \"index before merge has to match HEAD\" rule,\nthe first one could have been written as:\n\n\tgit-diff-index -p HEAD xyzzy ;# to compare with ours\n\nSo in that sense, I suspect it may not be too bad if we just\nchanged merge-one-file with the patch at the end.\n\nHowever, git-diff-index HEAD without paths restriction would\nshow everything the merge brought in, not just the conflicting\npath, so in that sense it may make things slightly harder for\nthe end user to use.\n\n---\n\ndiff --git a/git-merge-one-file.sh b/git-merge-one-file.sh\nindex c3eca8b..df6dd67 100755\n--- a/git-merge-one-file.sh\n+++ b/git-merge-one-file.sh\n@@ -79,11 +79,12 @@ case \"${1:-.}${2:-.}${3:-.}\" in\n \t\t;;\n \tesac\n \n-\t# We reset the index to the first branch, making\n-\t# git-diff-file useful\n-\tgit-update-index --add --cacheinfo \"$6\" \"$2\" \"$4\"\n-\t\tgit-checkout-index -u -f -- \"$4\" &&\n-\t\tmerge \"$4\" \"$orig\" \"$src2\"\n+\t# Leave the conflicts in stages; failed merge result can be\n+\t# seen by \"git-diff-index HEAD\" or \"git-diff-index MERGE_HEAD\"\n+\trm -fr \"$4\" &&\n+\t    git-cat-file blob \"$2\" >\"$4\" &&\n+\t    case \"$6\" in *?7??) chmod +x \"$4\" ;; esac &&\n+\t    merge \"$4\" \"$orig\" \"$src2\"\n \tret=$?\n \trm -f -- \"$orig\" \"$src2\"\n \n"},{"id":"12968","messageId":"Pine.LNX.4.64.0511291742000.3135@g5.osdl.org","threadId":"2704","inReplyTo":"20051130001503.28498.qmail@science.horizon.com","subject":"Re: git-name-rev off-by-one bug","fromName":"Linus Torvalds","fromEmail":"torvalds@osdl.org","sentAt":"2005-11-30T01:51:38Z","receivedAt":"2005-11-30T01:51:38Z","isPatch":false,"sender":{"key":"torvalds@linux-foundation.org","avatar":"https://avatars.githubusercontent.com/u/1024025?v=4"},"body":"\n\nOn Tue, 29 Nov 2005, linux@horizon.com wrote:\n>\n> You seem to be saying that producing a merge with conflict markers is\n> what you (almost) always want, so it's the default.  No objections.\n> \n> But why collapse the index and only keep stage2?  Why not leave all\n> stages in the index *and* the merge-with-conflict-markers in the working\n> directory?\n\nThat may actually work really well. It would also avoid one bug that we \nhave right now: if you fix things up by hand, but forget to explicitly do \na \"git-update-index filename\" or \"git commit filename\", a plain regular \n\"git commit\" will happily commit all the changes _except_ for the ones you \nhave merged manually. It's happened once to me.\n\nIf we left things in the index in an unmerged state, we'd be guaranteed to \neither _fail_ that git commit unless somebody has done the \ngit-update-index (or names the files specifically on the commit command \nline, which will do it for you).\n\nSo I think I agree. \n\nJunio?\n\nThe problem (I think) was that \"git-diff-file\" did bad things with \nunmerged entries. That's what the comment in git-merge-one-file implies. \nBut otherwise this should just make it so..\n\nDo you want to test this out?\n\n\t\tLinus\n\n---\ndiff --git a/git-merge-one-file.sh b/git-merge-one-file.sh\nindex c3eca8b..739a072 100755\n--- a/git-merge-one-file.sh\n+++ b/git-merge-one-file.sh\n@@ -79,11 +79,7 @@ case \"${1:-.}${2:-.}${3:-.}\" in\n \t\t;;\n \tesac\n \n-\t# We reset the index to the first branch, making\n-\t# git-diff-file useful\n-\tgit-update-index --add --cacheinfo \"$6\" \"$2\" \"$4\"\n-\t\tgit-checkout-index -u -f -- \"$4\" &&\n-\t\tmerge \"$4\" \"$orig\" \"$src2\"\n+\tmerge \"$4\" \"$orig\" \"$src2\"\n \tret=$?\n \trm -f -- \"$orig\" \"$src2\"\n \n"},{"id":"12969","messageId":"7vek4y51ph.fsf@assigned-by-dhcp.cox.net","threadId":"2704","inReplyTo":"Pine.LNX.4.64.0511291742000.3135@g5.osdl.org","subject":"Re: git-name-rev off-by-one bug","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2005-11-30T02:06:18Z","receivedAt":"2005-11-30T02:06:18Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Linus Torvalds <torvalds@osdl.org> writes:\n\n> If we left things in the index in an unmerged state, we'd be guaranteed to \n> either _fail_ that git commit unless somebody has done the \n> git-update-index (or names the files specifically on the commit command \n> line, which will do it for you).\n>\n> So I think I agree. \n\nI suspect we are saying the same thing.  Funny.\n"},{"id":"12970","messageId":"7v4q5u50gp.fsf@assigned-by-dhcp.cox.net","threadId":"2704","inReplyTo":"Pine.LNX.4.64.0511291742000.3135@g5.osdl.org","subject":"Re: git-name-rev off-by-one bug","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2005-11-30T02:33:10Z","receivedAt":"2005-11-30T02:33:10Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Linus Torvalds <torvalds@osdl.org> writes:\n\n> Junio?\n>\n> The problem (I think) was that \"git-diff-file\" did bad things with \n> unmerged entries. That's what the comment in git-merge-one-file implies. \n> But otherwise this should just make it so..\n>\n> Do you want to test this out?\n\nI have actually resolved one conflicting merge with this and it\nwas OK, except that it was a bit unpleasant when I first did\n\"git-diff-index HEAD\" without giving any path ;-), but the users\nwill get used to it.  Pushed out as a part of the proposed\nupdates collection.\n\nHere is what I wrote as the commit log message for the\nhand-resolved merge using this updated merge-one-file.\n\ncommit 6b48f6ff7ffff6ca0f9da53d9423a0474dd008fd\nMerge: b4f40b90ed1d9e1f3c0557e1ba064d169ba03a1c 99e01692063cc48adee19e1f738472a579c14ca2\nAuthor: Junio C Hamano <junkio@cox.net>\nDate:   Tue Nov 29 18:25:29 2005 -0800\n\n    Merge branch 'jc/subdir'\n    \n    This one is done with the updated merge-one-file, which leaves\n    unmerged entries in the index file to prevent unresolved merge\n    from getting committed by mistake.\n    \n    After \"git pull ...\" fails, earlier the user said:\n    \n    \t$ git-diff\n    \n    to see half-merged state.  Now git-diff just says:\n    \n    \t$ git-diff\n    \t* Unmerged path ls-tree.c\n    \n    In order to get the earlier \"show me the failed merge relative\n    to my HEAD\", you can say:\n    \n    \t$ git-diff HEAD ls-tree.c\n    \n    Signed-off-by: Junio C Hamano <junkio@cox.net>\n"},{"id":"12972","messageId":"Pine.LNX.4.64.0511291852530.3099@g5.osdl.org","threadId":"2704","inReplyTo":"7v4q5u50gp.fsf@assigned-by-dhcp.cox.net","subject":"Re: git-name-rev off-by-one bug","fromName":"Linus Torvalds","fromEmail":"torvalds@osdl.org","sentAt":"2005-11-30T03:12:45Z","receivedAt":"2005-11-30T03:12:45Z","isPatch":false,"sender":{"key":"torvalds@linux-foundation.org","avatar":"https://avatars.githubusercontent.com/u/1024025?v=4"},"body":"\n\nOn Tue, 29 Nov 2005, Junio C Hamano wrote:\n> \n> I have actually resolved one conflicting merge with this and it\n> was OK, except that it was a bit unpleasant when I first did\n> \"git-diff-index HEAD\" without giving any path ;-),\n\nWhat does \"git-diff-files\" do? Just output a lot of nasty \"unmerged\" \nmessages?\n\nThe _nice_ thing to do would be to output one \"unmerged\" message, but \nthen diff against stage2 if it exists (and it basically always should, \nsince otherwise we wouldn't have gotten a merge error).\n\nIf it did that, then you'd have the best of both world: the old nice \"git \ndiff\" behaviour _and_ being safe (and saying that it's unmerged).\n\nSomething like this (untested, of course).\n\nIt _should_ write out\n\n\t* Unmerged path <filename>\n\nfollowed by a regular diff, exactly like you'd want.\n\n[ This all assumes that merge-one-file leaves the stages right. I think my \n  patch to do that was just broken. Yours was probably not. ]\n\n\t\tLinus\n\n---\ndiff --git a/diff-files.c b/diff-files.c\nindex 38599b5..8a78326 100644\n--- a/diff-files.c\n+++ b/diff-files.c\n@@ -95,11 +95,23 @@ int main(int argc, const char **argv)\n \n \t\tif (ce_stage(ce)) {\n \t\t\tshow_unmerge(ce->name);\n-\t\t\twhile (i < entries &&\n-\t\t\t       !strcmp(ce->name, active_cache[i]->name))\n+\t\t\twhile (i < entries) {\n+\t\t\t\tstruct cache_entry *nce = active_cache[i];\n+\n+\t\t\t\tif (strcmp(ce->name, nce->name))\n+\t\t\t\t\tbreak;\n+\t\t\t\t/* Prefer to diff against stage 2 (original branch) */\n+\t\t\t\tif (ce_stage(nce) == 2)\n+\t\t\t\t\tce = nce;\n \t\t\t\ti++;\n-\t\t\ti--; /* compensate for loop control increments */\n-\t\t\tcontinue;\n+\t\t\t}\n+\t\t\t/*\n+\t\t\t * Compensate for loop update\n+\t\t\t */\n+\t\t\ti--;\n+\t\t\t/*\n+\t\t\t * Show the diff for the 'ce' we chose\n+\t\t\t */\n \t\t}\n \n \t\tif (lstat(ce->name, &st) < 0) {\n"},{"id":"12973","messageId":"20051130031559.26411.qmail@science.horizon.com","threadId":"2704","inReplyTo":"7v4q5u50gp.fsf@assigned-by-dhcp.cox.net","subject":"Re: git-name-rev off-by-one bug","fromName":"","fromEmail":"linux@horizon.com","sentAt":"2005-11-30T03:15:59Z","receivedAt":"2005-11-30T03:15:59Z","isPatch":false,"sender":{"key":"linux@horizon.com","avatar":null},"body":">   This one is done with the updated merge-one-file, which leaves\n>   unmerged entries in the index file to prevent unresolved merge\n>   from getting committed by mistake.\n>   \n>   After \"git pull ...\" fails, earlier the user said:\n>   \n>   \t$ git-diff\n>   \n>   to see half-merged state.  Now git-diff just says:\n>   \n>   \t$ git-diff\n>   \t* Unmerged path ls-tree.c\n>   \n>   In order to get the earlier \"show me the failed merge relative\n>   to my HEAD\", you can say:\n>   \n>   \t$ git-diff HEAD ls-tree.c\n\nCool!  You all know I like this change, mostly because it makes git's\nmerging conceptually cleaner and easier to explain.\n\nLooking at git, the difference between it and other SCMs is the emphasis\non merging over editing.  The tools for local development are a bit\nprimitive in core git, but that's a well-understood problem and the\ntools can be implemented as needed.\n\nWhat makes git special is the assumption that a patch is going to pass\nthrough several people on its way from the text editor to the release,\nso merging is actually more important than initial writing.\n\nRather than saying \"Linus doesn't scale\" and giving up, it's seen as an\nAmdahl's law problem - the goal is to remove as much work from Linus as\npossible and thus make him scale.  (The shorter and earther way to say\nthis is that Linus is a lazy bastard, which is no surprise to anyone\nwho's seen him try to hide behind a podium. ;-) )\n\nAnd an essential part of making that work is a good toolkit for dealing\nwith merging, and particularly in-progress merges.  By having the\nconcept of an unmerged index, git lets you develop merging algorithms\nin a modular way, as opposed to \"one big hairy pile of magic DWIMmery\"\nthat people are afraid to touch.\n\nFor example, one thing I'm sure will arrive fairly soon is file-type\nspecific merge algorithms.  For something like a .po file where the\norder of sections doesn't matter, merging ad->abd and ad->acd can be\nfully automated.\n\nThere are a number of good idea in git, but from what I've seen so far,\n\"git-read-tree -m\" is the most important one.\n\n\nMaking git-diff Do The Right Thing is a relatively minor matter.\n"},{"id":"12975","messageId":"Pine.LNX.4.64.0511292031280.3099@g5.osdl.org","threadId":"2704","inReplyTo":"Pine.LNX.4.64.0511291852530.3099@g5.osdl.org","subject":"Re: git-name-rev off-by-one bug","fromName":"Linus Torvalds","fromEmail":"torvalds@osdl.org","sentAt":"2005-11-30T05:06:10Z","receivedAt":"2005-11-30T05:06:10Z","isPatch":false,"sender":{"key":"torvalds@linux-foundation.org","avatar":"https://avatars.githubusercontent.com/u/1024025?v=4"},"body":"\n\nOn Tue, 29 Nov 2005, Linus Torvalds wrote:\n> \n> Something like this (untested, of course).\n> \n> It _should_ write out\n> \n> \t* Unmerged path <filename>\n> \n> followed by a regular diff, exactly like you'd want.\n\nThe more I thinking about this, the more I think this is a wonderful \napproach, but it would be even better to add a flag to let it choose \nbetween diffing against stage2 by default or diffing against stage3 (and \nhey, maybe even diffing against the original).\n\nIn fact, here's a patch that does that, and also makes the \"resolve\" merge \ncreate these kinds of merges. As usual, my python knowledge is useless, \nsince the only thing I know about python is that thou shalt not count to \nfour. As a result, the standard recursive merge doesn't do this yet ;(\n\nThe magic incantation is to just do\n\n\tgit diff\n\nand you'll get a diff against the first branch. If you want a diff against \nthe second branch, just use the \"-2\" option, and if you want a diff \nagainst the common base (which is actually surprisingly useful, I noticed, \nwhen I tried this with a conflict), use \"-0\".\n\nI've also changed \"git diff\" to _not_ drop the \"-M\" and \"-p\" options just \nbecause you give some other diff option. That was always a mistake. If you \nreally want the raw git diff format, use the raw \"git-diff-xyz\" programs \ndirectly.\n\nWhaddaya think? I really like it. Here's an example, where I merged two \nbranches that had the file \"hello\" in it, and the first branch had:\n\n\tHi there\n\tThis is the master branch\n\nand the second one had\n\n\tHi there\n\tThis is the 'other' branch\n\nand the base version had just the \"Hi there\", of course.\n\nThe default (or \"-1\" arg) behaviour is:\n\n\t[torvalds@g5 test-merge]$ git diff\n\t* Unmerged path hello\n\tdiff --git a/hello b/hello\n\tindex 7cebcf8..3fa4697 100644\n\t--- a/hello\n\t+++ b/hello\n\t@@ -1,2 +1,6 @@\n\t Hi there\n\t+<<<<<<< hello\n\t This is the master branch\n\t+=======\n\t+This is the 'other' branch\n\t+>>>>>>> .merge_file_fJWiNf\n\nwhich is obvious enough. You see exactly the conflict, and you see the \npart of the first branch that is unchanged.\n\nDiffing against the original gives you\n\n\t[torvalds@g5 test-merge]$ git diff -0\n\t* Unmerged path hello\n\tdiff --git a/hello b/hello\n\tindex 6530b63..3fa4697 100644\n\t--- a/hello\n\t+++ b/hello\n\t@@ -1 +1,6 @@\n\t Hi there\n\t+<<<<<<< hello\n\t+This is the master branch\n\t+=======\n\t+This is the 'other' branch\n\t+>>>>>>> .merge_file_fJWiNf\n\nwhich I actually found really readable. I realize that this is a really \nstupid example, but for a lot of trivial merges, this won't be _that_ far \noff, and it basically shows what happened in both branches, and ignores \nwhat neither side changed.\n\nThe \"-2\" in this case is just the same as \"-1\" except obviously the \"+\" \ncharacters are situated differently. Still useful (especially if the \nchanges were more complex).\n\nMe likee. Hope you guys do too.\n\n(And this is quite independently of the advantage that you can't commit an \nunmerged state by mistake, which is perhaps an even bigger one).\n\n\t\tLinus\n\n---\ndiff --git a/Documentation/diff-options.txt b/Documentation/diff-options.txt\nindex 6b496ed..afc7334 100644\n--- a/Documentation/diff-options.txt\n+++ b/Documentation/diff-options.txt\n@@ -18,6 +18,12 @@\n \tobject name of pre- and post-image blob on the \"index\"\n \tline when generating a patch format output.\t\n \n+-0 -1 -2::\n+\tWhen an unmerged entry is seen, diff against the base version,\n+\tthe \"first branch\" or the \"second branch\" respectively.\n+\n+\tThe default is to diff against the first branch.\n+\n -B::\n \tBreak complete rewrite changes into pairs of delete and create.\n \ndiff --git a/diff-files.c b/diff-files.c\nindex 38599b5..d744636 100644\n--- a/diff-files.c\n+++ b/diff-files.c\n@@ -13,6 +13,7 @@ COMMON_DIFF_OPTIONS_HELP;\n \n static struct diff_options diff_options;\n static int silent = 0;\n+static int diff_unmerged_stage = 2;\n \n static void show_unmerge(const char *path)\n {\n@@ -46,7 +47,13 @@ int main(int argc, const char **argv)\n \t\t\targc--;\n \t\t\tbreak;\n \t\t}\n-\t\tif (!strcmp(argv[1], \"-q\"))\n+\t\tif (!strcmp(argv[1], \"-0\"))\n+\t\t\tdiff_unmerged_stage = 1;\n+\t\telse if (!strcmp(argv[1], \"-1\"))\n+\t\t\tdiff_unmerged_stage = 2;\n+\t\telse if (!strcmp(argv[1], \"-2\"))\n+\t\t\tdiff_unmerged_stage = 3;\n+\t\telse if (!strcmp(argv[1], \"-q\"))\n \t\t\tsilent = 1;\n \t\telse if (!strcmp(argv[1], \"-r\"))\n \t\t\t; /* no-op */\n@@ -95,11 +102,23 @@ int main(int argc, const char **argv)\n \n \t\tif (ce_stage(ce)) {\n \t\t\tshow_unmerge(ce->name);\n-\t\t\twhile (i < entries &&\n-\t\t\t       !strcmp(ce->name, active_cache[i]->name))\n+\t\t\twhile (i < entries) {\n+\t\t\t\tstruct cache_entry *nce = active_cache[i];\n+\n+\t\t\t\tif (strcmp(ce->name, nce->name))\n+\t\t\t\t\tbreak;\n+\t\t\t\t/* Prefer to diff against the proper unmerged stage */\n+\t\t\t\tif (ce_stage(nce) == diff_unmerged_stage)\n+\t\t\t\t\tce = nce;\n \t\t\t\ti++;\n-\t\t\ti--; /* compensate for loop control increments */\n-\t\t\tcontinue;\n+\t\t\t}\n+\t\t\t/*\n+\t\t\t * Compensate for loop update\n+\t\t\t */\n+\t\t\ti--;\n+\t\t\t/*\n+\t\t\t * Show the diff for the 'ce' we chose\n+\t\t\t */\n \t\t}\n \n \t\tif (lstat(ce->name, &st) < 0) {\ndiff --git a/git-diff.sh b/git-diff.sh\nindex b3ec84b..efe8f75 100755\n--- a/git-diff.sh\n+++ b/git-diff.sh\n@@ -3,12 +3,13 @@\n # Copyright (c) 2005 Linus Torvalds\n # Copyright (c) 2005 Junio C Hamano\n \n+# Some way to turn these off?\n+default_flags=\"-M -p\"\n+\n rev=$(git-rev-parse --revs-only --no-flags --sq \"$@\") || exit\n-flags=$(git-rev-parse --no-revs --flags --sq \"$@\")\n+flags=$(git-rev-parse --no-revs --flags --sq $default_flags \"$@\")\n files=$(git-rev-parse --no-revs --no-flags --sq \"$@\")\n \n-: ${flags:=\"'-M' '-p'\"}\n-\n # I often say 'git diff --cached -p' and get scolded by git-diff-files, but\n # obviously I mean 'git diff --cached -p HEAD' in that case.\n case \"$rev\" in\ndiff --git a/git-merge-one-file.sh b/git-merge-one-file.sh\nindex c3eca8b..739a072 100755\n--- a/git-merge-one-file.sh\n+++ b/git-merge-one-file.sh\n@@ -79,11 +79,7 @@ case \"${1:-.}${2:-.}${3:-.}\" in\n \t\t;;\n \tesac\n \n-\t# We reset the index to the first branch, making\n-\t# git-diff-file useful\n-\tgit-update-index --add --cacheinfo \"$6\" \"$2\" \"$4\"\n-\t\tgit-checkout-index -u -f -- \"$4\" &&\n-\t\tmerge \"$4\" \"$orig\" \"$src2\"\n+\tmerge \"$4\" \"$orig\" \"$src2\"\n \tret=$?\n \trm -f -- \"$orig\" \"$src2\"\n \n"},{"id":"12976","messageId":"7vslte1y5z.fsf@assigned-by-dhcp.cox.net","threadId":"2704","inReplyTo":"Pine.LNX.4.64.0511292031280.3099@g5.osdl.org","subject":"Re: git-name-rev off-by-one bug","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2005-11-30T05:51:04Z","receivedAt":"2005-11-30T05:51:04Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Linus Torvalds <torvalds@osdl.org> writes:\n\n> Whaddaya think? I really like it.\n\nYes.  Maybe split this into 3 pieces.  I do not want to waste\nyour time with that, so will take the liberty to do so myself,\nwith appropriate commit log messages, if you do not mind.\n\n 1. give diff-files -[012] flags.\n 2. merge-one-file leaves unmerged index entries.\n 3. always use -M -p in git-diff.\n\nI do not have any issue against #1.\n\nRegarding #2, in an earlier message you said something about\n\"patch to do that was just broken\" which I did not understand; I\nthink your patch I am replying to is doing the right thing.  That\ncase arm is dealing with a path that exists in \"our\" branch and\nthe working tree blob should be the same as recorded in the\nHEAD, so I did not have to do the unpack-cat-chmod like I did in\nmine.  Am I simply confused?\n\nAbout #3, I am not quite sure.  I often use --name-status and I\ndo _not_ want -p to kick in when I do so.  How about something\nlike this?\n\n---\n\ndiff --git a/git-diff.sh b/git-diff.sh\nindex b3ec84b..8e0fe34 100755\n--- a/git-diff.sh\n+++ b/git-diff.sh\n@@ -7,8 +7,6 @@ rev=$(git-rev-parse --revs-only --no-fla\n flags=$(git-rev-parse --no-revs --flags --sq \"$@\")\n files=$(git-rev-parse --no-revs --no-flags --sq \"$@\")\n \n-: ${flags:=\"'-M' '-p'\"}\n-\n # I often say 'git diff --cached -p' and get scolded by git-diff-files, but\n # obviously I mean 'git diff --cached -p HEAD' in that case.\n case \"$rev\" in\n@@ -20,6 +18,21 @@ case \"$rev\" in\n \tesac\n esac\n \n+# If we do not have --name-status, --name-only nor -r, default to -p.\n+# If we do not have -B nor -C, default to -M.\n+case \" $flags \" in\n+*\" '--name-status' \"* | *\" '--name-only' \"* | *\" '-r' \"* )\n+\t;;\n+*)\n+\tflags=\"$flags '-p'\" ;;\n+esac\n+case \" $flags \" in\n+*\" '-\"[BCM]* | *\" '--find-copies-harder' \"*)\n+\t;; # something like -M50.\n+*)\n+\tflags=\"$flags '-M'\" ;;\n+esac\n+\n case \"$rev\" in\n ?*' '?*' '?*)\n \techo >&2 \"I don't understand\"\n"},{"id":"12978","messageId":"20051130060906.13277.qmail@science.horizon.com","threadId":"2704","inReplyTo":"Pine.LNX.4.64.0511292031280.3099@g5.osdl.org","subject":"Re: git-name-rev off-by-one bug","fromName":"","fromEmail":"linux@horizon.com","sentAt":"2005-11-30T06:09:06Z","receivedAt":"2005-11-30T06:09:06Z","isPatch":false,"sender":{"key":"linux@horizon.com","avatar":null},"body":"> +-0 -1 -2::\n> +\tWhen an unmerged entry is seen, diff against the base version,\n> +\tthe \"first branch\" or the \"second branch\" respectively.\n> +\n> +\tThe default is to diff against the first branch.\n> +\n\nEr... why are these flags zero-based?\n\ngit-ls-files -s displays them as \"1\", \"2\" and \"3\".  All the docs talk\nabout \"stage1\", \"stage2\" and \"stage3\".\n\nChange the nomenclature if you want, but this mixed messages business is\nkind of weird...\n\n(Heartened by the response to my previous question of \"why do you do\nthis thing that makes no sense to me\", I'm going to be bold and not ask\nwhy this is a good idea.)\n"},{"id":"12977","messageId":"7vek4y1x79.fsf@assigned-by-dhcp.cox.net","threadId":"2704","inReplyTo":"7vslte1y5z.fsf@assigned-by-dhcp.cox.net","subject":"Re: git-name-rev off-by-one bug","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2005-11-30T06:11:54Z","receivedAt":"2005-11-30T06:11:54Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Junio C Hamano <junkio@cox.net> writes:\n\n> Linus Torvalds <torvalds@osdl.org> writes:\n>\n>> Whaddaya think? I really like it.\n>\n> Yes.  Maybe split this into 3 pieces.  I do not want to waste\n> your time with that, so will take the liberty to do so myself,\n> with appropriate commit log messages, if you do not mind.\n>\n>  1. give diff-files -[012] flags.\n>  2. merge-one-file leaves unmerged index entries.\n>  3. always use -M -p in git-diff.\n>\n> I do not have any issue against #1.\n\nActually there is one.  If we are asked to do diff -1 and an\nunmerged path does not have stage #2 but stage #1 entry exists,\nwe would end up showing that stage #1, without telling the user\nthat we are showing something different from what was asked.\nHow about doing something like this, on top of yours?\n\n--- diff-files.c\n+++ diff-files.c\n@@ -117,8 +117,11 @@\n \t\t\t */\n \t\t\ti--;\n \t\t\t/*\n-\t\t\t * Show the diff for the 'ce' we chose\n+\t\t\t * Show the diff for the 'ce' if we found the one\n+\t\t\t * from the desired stage.\n \t\t\t */\n+\t\t\tif (ce_stage(ce) != diff_unmerged_stage)\n+\t\t\t\tcontinue;\n \t\t}\n \n \t\tif (lstat(ce->name, &st) < 0) {\n"},{"id":"12979","messageId":"7vwtiqzljr.fsf@assigned-by-dhcp.cox.net","threadId":"2704","inReplyTo":"20051130060906.13277.qmail@science.horizon.com","subject":"Re: git-name-rev off-by-one bug","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2005-11-30T06:39:36Z","receivedAt":"2005-11-30T06:39:36Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"linux@horizon.com writes:\n\n>> +-0 -1 -2::\n>> +\tWhen an unmerged entry is seen, diff against the base version,\n>> +\tthe \"first branch\" or the \"second branch\" respectively.\n>> +\n>> +\tThe default is to diff against the first branch.\n>> +\n>\n> Er... why are these flags zero-based?\n\nBecause -1 means \"first branch\" (usually \"ours\", aka HEAD), and\n-2 means \"second branch\" (\"theirs\", aka MERGE_HEAD), and -0 is\nfor the base (aka merge base)?\n\nBut I think you are right.  The numeric parameters should match\nstage number for consistency.\n\nHow about if I redo the patch to make diff-files accept -1/-2/-3\ninstead, and in addition accept \"--base\", \"--ours\", and\n\"--theirs\" as synonyms?\n\nSide note.  diff3 says MINE OLDER YOURS and the way to remember\nthe order is they are alphabetical.  We can say the same for\nbase, ours and theirs.\n"},{"id":"12981","messageId":"7vfypey573.fsf@assigned-by-dhcp.cox.net","threadId":"2704","inReplyTo":"Pine.LNX.4.64.0511291852530.3099@g5.osdl.org","subject":"Re: git-name-rev off-by-one bug","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2005-11-30T07:18:08Z","receivedAt":"2005-11-30T07:18:08Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Linus Torvalds <torvalds@osdl.org> writes:\n\n> On Tue, 29 Nov 2005, Junio C Hamano wrote:\n>> \n>> I have actually resolved one conflicting merge with this and it\n>> was OK, except that it was a bit unpleasant when I first did\n>> \"git-diff-index HEAD\" without giving any path ;-),\n>\n> What does \"git-diff-files\" do? Just output a lot of nasty \"unmerged\" \n> messages?\n\nThat was not what was unpleasant.  What was unpleasant was those\n\"unmerged\" messages were buried under heap of normal diffs,\nshowing the successfully merged entries as the result of merge.\n\nI am inclined to munge your patch to do this:\n\n * Change -0/-1/-2 to -1/-2/-3 to be consistent with stage\n   numbers, for technically minded.\n\n * Give --base, --ours, and --theirs as synonyms for -1/-2/-3,\n   for end users.\n\n * Change it not to pick other unmerged stage (I sent a separate\n   message about this already).\n\n * Change the diff_unmerged_stage default to 0.  While you are\n   inspecting a conflicted merge, you need to give --ours (or\n   -2) explicitly.  Alternatively we could first check if the\n   whole index is unmerged and make it default to 2 without\n   flags, but that would mean inspecting 19K entries first\n   before starting the main loop for the kernel for normal case.\n   With hot cache it is fine, so I'll try it first.\n\n   This \"with unmerged defaults to 2 otherwise defaults to 0\"\n   behaviour needs to be made overridable with an option, say -0\n   (or --merged, but that is overkill); otherwise you cannot get\n   diffs for merged paths until the index file is unmerged.\n\n * When diff_unmerged_stage is zero, keep the current behaviour.\n   Show diff for only specified stage when diff_unmerged_stage\n   is not zero.\n"},{"id":"12983","messageId":"7vek4ywmxx.fsf@assigned-by-dhcp.cox.net","threadId":"2704","inReplyTo":"7voe43iyyu.fsf@assigned-by-dhcp.cox.net","subject":"Re: git-name-rev off-by-one bug","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2005-11-30T08:37:46Z","receivedAt":"2005-11-30T08:37:46Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Junio C Hamano <junkio@cox.net> writes:\n\n> On a related topic of removing unwanted paths, earlier I said\n> 2-way is used to make sure \"git checkout\" takes your changes\n> with you when you switch branches.  As a natural consequence of\n> this, if you do not have any local changes, \"git checkout\"\n> without \"-f\" does the right thing -- it removes unwanted paths\n> that existed in the original branch but not in the branch you\n> are switching to.\n\nHere is an unsolicited advice (\"tip of the day\").\n\nI was on a branch which had some local \"throwaway\" changes, and\nI wanted to switch back to the master branch.  To be honest, I\neven forgot I had local changes there.  So I ran \"git checkout\",\nand here is what happened.\n\n        junio@siamese:~/git$ git checkout master\n        fatal: Entry 'Documentat...' not uptodate. Cannot merge.\n\nThe easiest is \"git checkout -f master\" at this point, but I\nusually do not do that.  If that entry \"git checkout\" complains\nabout is something that is not in the master branch and I have\nthrowaway changes, \"git checkout -f master\" would leave that\nfile with throwaway changes behind.  So I did this first:\n\n        junio@siamese:~/git$ git reset --hard\n\nThis would sync my working tree to the current branch.  Then\n\n        junio@siamese:~/git$ git checkout master\n\nwould switch branches properly, removing that new file that\nshould not exist in the working tree.\n"},{"id":"12986","messageId":"7vr78yv72n.fsf@assigned-by-dhcp.cox.net","threadId":"2704","inReplyTo":"7vfypey573.fsf@assigned-by-dhcp.cox.net","subject":"Re: git-name-rev off-by-one bug","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2005-11-30T09:05:52Z","receivedAt":"2005-11-30T09:05:52Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Junio C Hamano <junkio@cox.net> writes:\n\n> Linus Torvalds <torvalds@osdl.org> writes:\n>\n>> On Tue, 29 Nov 2005, Junio C Hamano wrote:\n>>> \n>>> I have actually resolved one conflicting merge with this and it\n>>> was OK, except that it was a bit unpleasant when I first did\n>>> \"git-diff-index HEAD\" without giving any path ;-),\n>>\n>> What does \"git-diff-files\" do? Just output a lot of nasty \"unmerged\" \n>> messages?\n>\n> That was not what was unpleasant.  What was unpleasant was those\n> \"unmerged\" messages were buried under heap of normal diffs,\n> showing the successfully merged entries as the result of merge.\n>\n> I am inclined to munge your patch to do this:\n\nThis I have done, and pushed out to \"pu\" for tonight.  After\ndoing some more test I'll have this graduate to \"master\"\nsometime tomorrow along with other accumulated changes.\n"},{"id":"12985","messageId":"7vek4yv5dn.fsf@assigned-by-dhcp.cox.net","threadId":"2704","inReplyTo":"7vfypey573.fsf@assigned-by-dhcp.cox.net","subject":"Re: git-name-rev off-by-one bug","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2005-11-30T09:42:28Z","receivedAt":"2005-11-30T09:42:28Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Junio C Hamano <junkio@cox.net> writes:\n\n> Linus Torvalds <torvalds@osdl.org> writes:\n>\n>> What does \"git-diff-files\" do? Just output a lot of nasty \"unmerged\" \n>> messages?\n>\n> That was not what was unpleasant.  What was unpleasant was those\n> \"unmerged\" messages were buried under heap of normal diffs,\n> showing the successfully merged entries as the result of merge.\n\nCorrection.  The above is a faulty memory, and does not happen,\nwith or without your \"stage0 or stage2\" patch.  Cleanly merged\npaths are written out to working tree and collapsed to stage0 in\nthe index, so diff-files wouldn't have shown them at all.  \n\nSorry about the confused statement.  What I saw was my local\nmodifications on the paths unrelated to the merge.\n"},{"id":"12988","messageId":"20051130131045.28149.qmail@science.horizon.com","threadId":"2704","inReplyTo":"7vwtiqzljr.fsf@assigned-by-dhcp.cox.net","subject":"More merge questions","fromName":"","fromEmail":"linux@horizon.com","sentAt":"2005-11-30T13:10:45Z","receivedAt":"2005-11-30T13:10:45Z","isPatch":false,"sender":{"key":"linux@horizon.com","avatar":null},"body":"I'm working my way through a thorough understanding of merging.\n\nFirst I got git-read-tree's 3-way merge down to 6 conditionals, where\na missing entry is considered equal to a missing entry, and a missing\nindex entry is considered clean.\n\na) If stage2 == stage3, use stage2\nb) If stage1 == stage3, use stage2\nc) If the index entry exists and is dirty (working dir changes), FAIL\nd) If stage1 == stage2, use stage3\ne) If trivial-only, FAIL\nf) Return unmerged result for 3-way resolution by git-merge-index.\n\nCase c is needed so you don't change the world out from under\nyour working directory changes.  You could move it earlier and\nmake things strictire, but that's the minimal restriction.\n\nThen I started thinking about 2-way merge, and how that differed\nfrom a 3-way merge where stage2 was the previous index contents.\n\nIf you apply the same rules (with trivial-only true), the only differences\nto the big 22-case table in the git-read-tree docs are:\n\n3) This says that if stage1 and state3 exist, use stage3.\n   3-way says if they're equal, delete the file, while if they're\n   unequal, it's fail.\n\nIf 3-way git-merge-index were allowed, then the conditions that would\nchange to do it are cases 8 and 12.\n\nThe full list of cases and the conditional that applies, is:\n\n0) a\n1) d\n2) a\n3) see above.  It's b or e by my logic, but d by the table.\n\n4) b\n5) b\n6) a\n7) a\n8) e\n9) c\n\n10) d\n11) c\n12) e\n13) c\n\n14) a or b\n15) a or b\n\n16) e\n17) c\n18) a\n19) a\n20) d\n21) c\n\nGiven that it all matches up so nicely, I'd like to honestly ask if\ncase 3 of the conditions is correct.  I'd think that if I deleted\na file form te index, and the file wasn't changed on the head I'm\ntracking, the right resolution is to keep it deleted.  Why override\nmy deletion?\n\nSorry if this is a dumb question, but it's not obvious to me.\n"},{"id":"12994","messageId":"Pine.LNX.4.64.0511300808350.3099@g5.osdl.org","threadId":"2704","inReplyTo":"7vslte1y5z.fsf@assigned-by-dhcp.cox.net","subject":"Re: git-name-rev off-by-one bug","fromName":"Linus Torvalds","fromEmail":"torvalds@osdl.org","sentAt":"2005-11-30T16:08:59Z","receivedAt":"2005-11-30T16:08:59Z","isPatch":false,"sender":{"key":"torvalds@linux-foundation.org","avatar":"https://avatars.githubusercontent.com/u/1024025?v=4"},"body":"\n\nOn Tue, 29 Nov 2005, Junio C Hamano wrote:\n> \n> About #3, I am not quite sure.  I often use --name-status and I\n> do _not_ want -p to kick in when I do so.  How about something\n> like this?\n\nYes. I was thinking about something like that, but I decided it was too \nmuch work ;)\n\n\t\tLinus\n"},{"id":"12996","messageId":"Pine.LNX.4.64.0511300809300.3099@g5.osdl.org","threadId":"2704","inReplyTo":"20051130060906.13277.qmail@science.horizon.com","subject":"Re: git-name-rev off-by-one bug","fromName":"Linus Torvalds","fromEmail":"torvalds@osdl.org","sentAt":"2005-11-30T16:12:59Z","receivedAt":"2005-11-30T16:12:59Z","isPatch":false,"sender":{"key":"torvalds@linux-foundation.org","avatar":"https://avatars.githubusercontent.com/u/1024025?v=4"},"body":"\n\nOn Tue, 30 Nov 2005, linux@horizon.com wrote:\n>\n> > +-0 -1 -2::\n> > +\tWhen an unmerged entry is seen, diff against the base version,\n> > +\tthe \"first branch\" or the \"second branch\" respectively.\n> > +\n> > +\tThe default is to diff against the first branch.\n> \n> Er... why are these flags zero-based?\n\nBecause it makes more sense from a \"git diff\" standpoint to do that.\n\nThe fact that _internally_, git puts the first branch into \"stage 2\", and \nthe second one into \"stage 3\", that's very much a internal git \nimplementation issue that makes no sense to expose to a regular user.\n\n> git-ls-files -s displays them as \"1\", \"2\" and \"3\".  All the docs talk\n> about \"stage1\", \"stage2\" and \"stage3\".\n\nYes, but those are _technical_ docs, not docs aimed toward a user. Nobody \nsane uses \"git-ls-files --stage\" outside of a script, or unless they \nreally know git and are trying to debug something.\n\n>From a user standpoint, it makes a lot more sense to say \"primary branch\" \nand \"other branch\" , and then \"-1\" and \"-2\" make sense (and then the \"base \nof the merge\" makes sense as \"-0\").\n\n\t\tLinus\n"},{"id":"12995","messageId":"Pine.LNX.4.64.0511300813190.3099@g5.osdl.org","threadId":"2704","inReplyTo":"7vek4y1x79.fsf@assigned-by-dhcp.cox.net","subject":"Re: git-name-rev off-by-one bug","fromName":"Linus Torvalds","fromEmail":"torvalds@osdl.org","sentAt":"2005-11-30T16:13:32Z","receivedAt":"2005-11-30T16:13:32Z","isPatch":false,"sender":{"key":"torvalds@linux-foundation.org","avatar":"https://avatars.githubusercontent.com/u/1024025?v=4"},"body":"\n\nOn Tue, 29 Nov 2005, Junio C Hamano wrote:\n> \n> Actually there is one.  If we are asked to do diff -1 and an\n> unmerged path does not have stage #2 but stage #1 entry exists,\n> we would end up showing that stage #1, without telling the user\n> that we are showing something different from what was asked.\n> How about doing something like this, on top of yours?\n\nYes.\n\n\t\tLinus\n"},{"id":"12998","messageId":"Pine.LNX.4.64.0511301235390.25300@iabervon.org","threadId":"2704","inReplyTo":"7vhd9wngn6.fsf@assigned-by-dhcp.cox.net","subject":"Re: git-name-rev off-by-one bug","fromName":"Daniel Barkalow","fromEmail":"barkalow@iabervon.org","sentAt":"2005-11-30T17:46:00Z","receivedAt":"2005-11-30T17:46:00Z","isPatch":false,"sender":{"key":"barkalow@iabervon.org","avatar":"https://avatars.githubusercontent.com/u/55364219?v=4"},"body":"On Mon, 28 Nov 2005, Junio C Hamano wrote:\n\n> *1* It is a shame that the most comprehensive definition of\n> 3-way read-tree semantics is in t/t1000-read-tree-m-3way.sh test\n> script.\n\nIsn't Documentation/technical/trivial-merge.txt more comprehensive?\n\nProbably the tables in various other places should be replaced with \nreferences to this document.\n\n\t-Daniel\n"},{"id":"12999","messageId":"Pine.LNX.4.64.0511301302310.25300@iabervon.org","threadId":"2704","inReplyTo":"Pine.LNX.4.64.0511291742000.3135@g5.osdl.org","subject":"Re: git-name-rev off-by-one bug","fromName":"Daniel Barkalow","fromEmail":"barkalow@iabervon.org","sentAt":"2005-11-30T18:11:06Z","receivedAt":"2005-11-30T18:11:06Z","isPatch":false,"sender":{"key":"barkalow@iabervon.org","avatar":"https://avatars.githubusercontent.com/u/55364219?v=4"},"body":"On Tue, 29 Nov 2005, Linus Torvalds wrote:\n\n> If we left things in the index in an unmerged state, we'd be guaranteed to \n> either _fail_ that git commit unless somebody has done the \n> git-update-index (or names the files specifically on the commit command \n> line, which will do it for you).\n\nAt this point, we could have a \"git-merged-by-hand\" script that would take \nfilenames, check that they're unmerged now, and, if so, call \ngit-update-index for them. And it could have a -a to do all of the \nunmerged entries (i.e., \"I'm done merging by hand\"), and maybe also have a \nflag to git-commit that does this, so you can say, \"Commit the merge I did \nby hand, whatever filenames it used, but not any other changes I may have \nhad beforehand.\"\n\nThe \"merged-by-hand\" script would probably be a sensible place to complain \nabout leftover conflict markers (unless you force it).\n\n\t-Daniel\n*This .sig left intentionally blank*\n"},{"id":"13001","messageId":"Pine.LNX.4.64.0511301325580.25300@iabervon.org","threadId":"2704","inReplyTo":"20051130131045.28149.qmail@science.horizon.com","subject":"Re: More merge questions","fromName":"Daniel Barkalow","fromEmail":"barkalow@iabervon.org","sentAt":"2005-11-30T18:37:26Z","receivedAt":"2005-11-30T18:37:26Z","isPatch":false,"sender":{"key":"barkalow@iabervon.org","avatar":"https://avatars.githubusercontent.com/u/55364219?v=4"},"body":"On Wed, 30 Nov 2005, linux@horizon.com wrote:\n\n> Given that it all matches up so nicely, I'd like to honestly ask if\n> case 3 of the conditions is correct.  I'd think that if I deleted\n> a file form te index, and the file wasn't changed on the head I'm\n> tracking, the right resolution is to keep it deleted.  Why override\n> my deletion?\n\nYou're allowed to do the two-way merge with your index empty, and this \nmeans that you just hadn't read the ancestor, not that you want to remove \neverything. I'm not sure what this is useful for.\n\nYou're definitely allowed to do a three-way merge with your index empty, \nmeaning that you don't have any local changes at all, which lets you do a \nmerge in a temporary index that didn't exist before. (The two-way case is \nless interesting, because it's the same as just reading the new tree.)\n\n\t-Daniel\n*This .sig left intentionally blank*\n"},{"id":"13003","messageId":"7vsltdsxzb.fsf@assigned-by-dhcp.cox.net","threadId":"2704","inReplyTo":"Pine.LNX.4.64.0511301235390.25300@iabervon.org","subject":"Re: git-name-rev off-by-one bug","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2005-11-30T20:05:12Z","receivedAt":"2005-11-30T20:05:12Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Daniel Barkalow <barkalow@iabervon.org> writes:\n\n> On Mon, 28 Nov 2005, Junio C Hamano wrote:\n>\n>> *1* It is a shame that the most comprehensive definition of\n>> 3-way read-tree semantics is in t/t1000-read-tree-m-3way.sh test\n>> script.\n>\n> Isn't Documentation/technical/trivial-merge.txt more comprehensive?\n\nIt describes the multi-base extention while the old one was done\nbefore the multi-base, so content-wise it may be more up to date.\n\nOne thing I have most trouble with is that it is not obvious if\nthe table is covering all the cases.  You have to read from top\nto bottom and consider the first match as its fate [*1*].  I was\nabout to write \"with no match resulting in no merge\", but it is\nnot even obvious if there are cases that would fall off at the\nend from the table by just looking at it.  Even worse, if we add\n\"no match results in no merge\" at the end, by definition it\ncovers all the cases, but it is not obvious what those fall-off\ncases are (IOW, what kinds of conflict they are and why they are\nnot handled).\n\nAnother thing, perhaps more important, is taht it does not seem\nto talk about index and up-to-dateness requirements much; it\nsays something about what happens when \"no merge\" result is\ntaken, but it is not clear about other cases.  The table in\nt1000 test marks the case with \"must match X\" when index and\ntree X must agree at the path, and with \"must match X and be\nup-to-date\" when in addition the file in the working tree must\nmatch what is recorded in the index at the path (i.e. the former\ncan have local modification in the working tree as long as index\nentry and tree match).\n\nThis is vital in making sure that read-tree 3-way merge does not\nlose information from the working tree.  I am sure your updated\n*code* is doing the right thing, but the documentation is not\nclear about it.  E.g. case 3ALT in the table says \"take our\nbranch if the path does not exist in one or more of common\nancestors and the other branch does not have it\" without saying\nanything about index nor up-to-dateness requirements.  In this\ncase, the index must match HEAD but the working tree file is\nallowed to have local modification (t1000 table says \"must match\nA\").  If somebody wants to audit if the current read-tree.c does\nthe right thing for this case, he needs the documentation to\ntell him what should happen.  There may be thinko in the design\n(IOW, the index requirements the documentation places may not\nmake sense) that can be found during such an audit.  There may\nbe implementation error that the code does not match what the\ndocumentation says should happen.  Not having that information\nin the case table makes these verification difficult.\n\n> Probably the tables in various other places should be replaced with \n> references to this document.\n\nI agree 100% that having them scattered all over is bad and the\ntrivial-merge.txt is the logical place to consolidate them, but\nI do not think simply removing others and pointing at\ntrivial-merge.txt without updating it is good enough.\n\n[Footnote]\n\n*1* That is OK from an implementation point of view (i.e. we can\nlook at the table, and then go to C implementation and follow\nits if-elif chain to see if the same checks are done in the same\norder as specified in the document), but for somebody who wants\nto understand the semantics, i.e. what the thing it does means,\nby looking at the documentation it is harder to read.\n"},{"id":"13004","messageId":"7vek4xsx49.fsf@assigned-by-dhcp.cox.net","threadId":"2704","inReplyTo":"20051130131045.28149.qmail@science.horizon.com","subject":"Re: More merge questions","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2005-11-30T20:23:50Z","receivedAt":"2005-11-30T20:23:50Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"linux@horizon.com writes:\n\n> 3) This says that if stage1 and state3 exist, use stage3.\n>    3-way says if they're equal, delete the file, while if they're\n>    unequal, it's fail.\n>\n> Given that it all matches up so nicely, I'd like to honestly ask if\n> case 3 of the conditions is correct.  I'd think that if I deleted\n> a file form te index, and the file wasn't changed on the head I'm\n> tracking, the right resolution is to keep it deleted.  Why override\n> my deletion?\n>\n> Sorry if this is a dumb question, but it's not obvious to me.\n\nFunny that I asked exactly the same question when it was done\nfirst:\n\n\thttp://marc.theaimsgroup.com/?l=git&m=111804744926989\n\nIt was a question about then-current code, so other cases might\nhave been changed/corrected/enhanced since then, but I believe\nthe behaviour for the case in question here stays the same til\nthis day, and the response from Linus to that article still\napplies.\n\n\n\thttp://marc.theaimsgroup.com/?l=git&m=111807024201485\n\nI'll quote only the punch line here, but the whole thing is\nworth a read if you want to understand how this evolved and\nwhat the design choices and decisions were:\n\n  Right. We didn't lose anything hugely important. \n\n  In theory this could be a delete that we've missed, and we could add a \n  flag to actually reject this case. However, it's always easy to \"recover\" \n  deletes (just delete it again ;), so the loss of information is absolutely \n  minimal, and it allows starting from an empty index file.\n"},{"id":"13005","messageId":"Pine.LNX.4.64.0511301514500.25300@iabervon.org","threadId":"2704","inReplyTo":"7vsltdsxzb.fsf@assigned-by-dhcp.cox.net","subject":"Re: git-name-rev off-by-one bug","fromName":"Daniel Barkalow","fromEmail":"barkalow@iabervon.org","sentAt":"2005-11-30T21:06:39Z","receivedAt":"2005-11-30T21:06:39Z","isPatch":false,"sender":{"key":"barkalow@iabervon.org","avatar":"https://avatars.githubusercontent.com/u/55364219?v=4"},"body":"On Wed, 30 Nov 2005, Junio C Hamano wrote:\n\n> Daniel Barkalow <barkalow@iabervon.org> writes:\n> \n> > On Mon, 28 Nov 2005, Junio C Hamano wrote:\n> >\n> >> *1* It is a shame that the most comprehensive definition of\n> >> 3-way read-tree semantics is in t/t1000-read-tree-m-3way.sh test\n> >> script.\n> >\n> > Isn't Documentation/technical/trivial-merge.txt more comprehensive?\n> \n> It describes the multi-base extention while the old one was done\n> before the multi-base, so content-wise it may be more up to date.\n> \n> One thing I have most trouble with is that it is not obvious if\n> the table is covering all the cases.  You have to read from top\n> to bottom and consider the first match as its fate [*1*]. \n\nI actually had that problem with the original tables; there isn't a \ncanonical order in which to list a table of all of the possible matches \nand non-matches between items so as to be complete.\n\nPerhaps it ought to list, on each line, which previous cases would match, \nso that you could see that case 2 is really the conditions of 2 minus the \nconditions for 2ALT, which is \"all of the ancestors are empty, the head \nhas a directory/file conflict, and remote exists.\"\n\nIt can't fall off the table, because 1, 2, 3, 4, 6, 7, 9, and 11 cover all \nof the possibilities with respect to inputs being empty, and do not care \nabout matching between the inputs.\n\n> I was about to write \"with no match resulting in no merge\", but it is\n> not even obvious if there are cases that would fall off at the\n> end from the table by just looking at it.  Even worse, if we add\n> \"no match results in no merge\" at the end, by definition it\n> covers all the cases, but it is not obvious what those fall-off\n> cases are (IOW, what kinds of conflict they are and why they are\n> not handled).\n> \n> Another thing, perhaps more important, is taht it does not seem\n> to talk about index and up-to-dateness requirements much; it\n> says something about what happens when \"no merge\" result is\n> taken, but it is not clear about other cases.  The table in\n> t1000 test marks the case with \"must match X\" when index and\n> tree X must agree at the path, and with \"must match X and be\n> up-to-date\" when in addition the file in the working tree must\n> match what is recorded in the index at the path (i.e. the former\n> can have local modification in the working tree as long as index\n> entry and tree match).\n\nBut that is redundant information. I was actually confused by that part of \nthe table for a long time, because it was not clear that it followed a \ncouple of simple rules (which I give above the table), and weren't \nactually chosen on a case-by-case basis.\n\nThe implementation I did is actually much easier to verify, because it \ndoesn't go into each case for the index requirements, but checks the \nactual rules: the index must match either the head or (if there is one) \nthe merge result, and the index must not be dirty if there is a \"no merge\" \nresult. Therefore, you can't lose any work in the index (either you didn't \nhave any, or you did the same thing), and you can't lose any work in the \nworking tree (either you didn't have any, or we're not going to use the \nworking tree).\n\nLast time we discussed it (\"Multi-ancestor read-tree notes\"), you said:\n\n  I like the second sentence in three-way merge description.  That\n  is a very easy-to-understand description of what the index\n  requirements are.\n\n> This is vital in making sure that read-tree 3-way merge does not\n> lose information from the working tree.  I am sure your updated\n> *code* is doing the right thing, but the documentation is not\n> clear about it.  E.g. case 3ALT in the table says \"take our\n> branch if the path does not exist in one or more of common\n> ancestors and the other branch does not have it\" without saying\n> anything about index nor up-to-dateness requirements. \n\n\"If the index exists, it is an error for it not to match either the\n head or (if the merge is trivial) the result.\"\n\n\"A result of \"no merge\" is an error if the index is not empty and not\n up-to-date.\"\n\nSo the index is permitted to not exist (you missed this case), but if it \nexists, it must match HEAD (or, well, HEAD, which is the result). The \nindex need not be up-to-date (since the result is not \"no merge\"), so the \nworking tree doesn't matter.\n\n> > Probably the tables in various other places should be replaced with \n> > references to this document.\n> \n> I agree 100% that having them scattered all over is bad and the\n> trivial-merge.txt is the logical place to consolidate them, but\n> I do not think simply removing others and pointing at\n> trivial-merge.txt without updating it is good enough.\n\nCertainly, your complaints about the table should be addressed first. I \nthink I'd addressed all your complaints from last time, but at that point, \nwe got sidetracked into a discussion of the details of case #16.\n\n\t-Daniel\n*This .sig left intentionally blank*\n"},{"id":"13008","messageId":"7vy835okxs.fsf@assigned-by-dhcp.cox.net","threadId":"2704","inReplyTo":"Pine.LNX.4.64.0511301514500.25300@iabervon.org","subject":"Re: git-name-rev off-by-one bug","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2005-11-30T22:00:31Z","receivedAt":"2005-11-30T22:00:31Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Daniel Barkalow <barkalow@iabervon.org> writes:\n\n> I actually had that problem with the original tables; there isn't a \n> canonical order in which to list a table of all of the possible matches \n> and non-matches between items so as to be complete.\n>\n> Perhaps it ought to list, on each line, which previous cases would match, \n> so that you could see that case 2 is really the conditions of 2 minus the \n> conditions for 2ALT, which is \"all of the ancestors are empty, the head \n> has a directory/file conflict, and remote exists.\"\n\nSorry, I was not clear about it when I did that table the first\ntime.  2ALT was \"alternatives suggested to replace 2\" and listed\nin the same table for comparison purpose.\n\nThe original table was designed in a way that if you have a\nmatch on case N, there would not be any other case M that matches\nthe case, either N<M or M<N.  IOW, the order to read the table\ndid not matter.  At least that was the intention.\n\nIf you read \"missing\" = 0, \"exists\" = 1, and take OAB as bit2,\nbit1, and bit0, you can easily see the pattern in the table.  It\ncounts in binary, although bit1 has various subcases so the\ntable has more than 8 rows, and it is easy to see it covers all.\n\n> \"If the index exists, it is an error for it not to match either the\n>  head or (if the merge is trivial) the result.\"\n>\n> \"A result of \"no merge\" is an error if the index is not empty and not\n>  up-to-date.\"\n\nThat is good.\n\n> Certainly, your complaints about the table should be addressed first. I \n> think I'd addressed all your complaints from last time, but at that point, \n> we got sidetracked into a discussion of the details of case #16.\n\n... which was a good thing to think about in itself.  I feel I\nunderstand the new table a bit better.\n"},{"id":"13018","messageId":"Pine.LNX.4.64.0511301707020.25300@iabervon.org","threadId":"2704","inReplyTo":"7vy835okxs.fsf@assigned-by-dhcp.cox.net","subject":"Re: git-name-rev off-by-one bug","fromName":"Daniel Barkalow","fromEmail":"barkalow@iabervon.org","sentAt":"2005-11-30T23:12:57Z","receivedAt":"2005-11-30T23:12:57Z","isPatch":false,"sender":{"key":"barkalow@iabervon.org","avatar":"https://avatars.githubusercontent.com/u/55364219?v=4"},"body":"On Wed, 30 Nov 2005, Junio C Hamano wrote:\n\n> Daniel Barkalow <barkalow@iabervon.org> writes:\n> \n> > I actually had that problem with the original tables; there isn't a \n> > canonical order in which to list a table of all of the possible matches \n> > and non-matches between items so as to be complete.\n> >\n> > Perhaps it ought to list, on each line, which previous cases would match, \n> > so that you could see that case 2 is really the conditions of 2 minus the \n> > conditions for 2ALT, which is \"all of the ancestors are empty, the head \n> > has a directory/file conflict, and remote exists.\"\n> \n> Sorry, I was not clear about it when I did that table the first\n> time.  2ALT was \"alternatives suggested to replace 2\" and listed\n> in the same table for comparison purpose.\n\nI understood that; actually, when I found it, a number of the ALT cases \nhad been implemented, and some of them supplimented rather than replaced \nthe originals.\n\n> The original table was designed in a way that if you have a\n> match on case N, there would not be any other case M that matches\n> the case, either N<M or M<N.  IOW, the order to read the table\n> did not matter.  At least that was the intention.\n> \n> If you read \"missing\" = 0, \"exists\" = 1, and take OAB as bit2,\n> bit1, and bit0, you can easily see the pattern in the table.  It\n> counts in binary, although bit1 has various subcases so the\n> table has more than 8 rows, and it is easy to see it covers all.\n\nThe hard thing is to verify that all the subcases are listed. I switched \nthe orders of matching and non-matching, so that I could make it matching \nand need-not-match. Your table is actually missing a few cases: what \nhappens if O is missing, 2 has a directory, and 3 has a file? You note \nthat we have to be careful, but don't list the result (which is \"no \nmerge\").\n\nPerhaps the table would be clearer if the lines were grouped in \nexists/missing? (With 5ALT repeated in the 011 and 111 groups, since it \napplies to both) Then you would only need to look at 5 lines with \ncascading (in the most complex case), rather than having to read the whole \ntop of the table.\n\n(It is actually written like that, with the exception of 5ALT, 2ALT, and \n3ALT, but it's not visually obvious.)\n\nSo case 11 is really: All three exist. Head and remote don't match \n(-5ALT), no ancestor matches remote (-13), and no ancestor matches head \n(-14). Case 13 is really: All three exist. Head and remote don't match \n(-5ALT), there aren't different ancestors which match head and remote \n(-16), and an ancestor matches remote.\n\nThe tricky bit is really cases 2ALT and 3ALT, which can be used in cases \nwhere some but not all of the ancestors are empty, and can't be used if \nthere's a directory/file conflict; neither of these conditions matters for \nanything else in the table, so it's hard to fit this in. My strategy is to \nhave those as special cases, and have the rest of the table cover \neverything (rather than having case 2 require a directory/file conflict \nand case 7 require that no ancestor be empty, which would be accurate, but \nwould make it harder to check for missing cases).\n\n\t-Daniel\n*This .sig left intentionally blank*\n"},{"id":"13028","messageId":"7vu0dtl0o3.fsf@assigned-by-dhcp.cox.net","threadId":"2704","inReplyTo":"Pine.LNX.4.64.0511301707020.25300@iabervon.org","subject":"Re: git-name-rev off-by-one bug","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2005-12-01T07:46:36Z","receivedAt":"2005-12-01T07:46:36Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Delight in working on free software project is you have so many\ngood people with you that you can have many \"Aha, lightbulb!\"\nmoments.  This is one of them for me.  I realized where the\ntrouble I felt when reading your table came from; it was that I\nwas focused on the old way the table was organized too much.\n\nWhen one constructs a case table to make sure one covered\neverything, one first lists the variables and the possible\nvalues they can take, and make NxMxOxPx... grid.  In the\noriginal table I did, I chose what is in O and A and B as my\nvariables (and that's where my comment about O being bit2 etc\ncomes from).  I did not realize the semantics and algorithm you\nused can be better described by different set of variables\n(namely, how ancestors match the HEAD, and how the remote\nmatches the HEAD, if I understand correctly).  I had trouble\nunderstanding your version only because I kept thinking in terms\nof (O,A,B).\n\nSo after thinking about that...\n\n    Daniel Barkalow <barkalow@iabervon.org> writes:\n\n    > On Wed, 30 Nov 2005, Junio C Hamano wrote:\n    >\n    > Perhaps the table would be clearer if the lines were grouped\n    > in exists/missing? (With 5ALT repeated in the 011 and 111\n    > groups, since it applies to both) Then you would only need\n    > to look at 5 lines with cascading (in the most complex\n    > case), rather than having to read the whole top of the\n    > table.\n\nI think the current ordering of cases makes more sense.  If we\nforget about the case labels from the original table (and the\nway the original table classified cases), I suspect we could\nreorganize the cases to describe the semantics even better and\nclearer.  That is, not grouping by exists/missing, but grouping\nby matching/unmatching.\n\n> (It is actually written like that, with the exception of 5ALT, 2ALT, and \n> 3ALT, but it's not visually obvious.)\n\nYeah, I now realize that.\n\n> The tricky bit is really cases 2ALT and 3ALT, which can be used in cases \n> where some but not all of the ancestors are empty, and can't be used if \n> there's a directory/file conflict; neither of these conditions matters for \n> anything else in the table, so it's hard to fit this in. My strategy is to \n> have those as special cases, and have the rest of the table cover \n> everything (rather than having case 2 require a directory/file conflict \n> and case 7 require that no ancestor be empty, which would be accurate, but \n> would make it harder to check for missing cases).\n\nMakes sense.  Thanks for the clarification and lightbulb moment.\n"},{"id":"13037","messageId":"7vd5khjf9g.fsf@assigned-by-dhcp.cox.net","threadId":"2704","inReplyTo":"20051128234256.1508.qmail@science.horizon.com","subject":"Re: git-name-rev off-by-one bug","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2005-12-01T10:14:19Z","receivedAt":"2005-12-01T10:14:19Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"linux@horizon.com writes:\n\n> Anyway, if it's portable enough, it's faster.  Ah... I just found discussion\n> of this in late September, but it's not clear what the resolution was.\n> http://marc.theaimsgroup.com/?t=112746188000003\n\nAlthough updating our shell scripts to this century is lower on\nmy priority scale, ideally I'd want to see things work with\ndash, not because I do not like bash/ksh, but because it seems\nthe smallest minimally POSIXy shell.\n\nSpeaking of shell gotchas, I do not know what the resolution was\non the problem Merlyn was having the other day in \"lost again on\nsyntax change - local repository?\" thread, which seemed that the\nfailure described in <868xv86dam.fsf@blue.stonehenge.com> was\nhis bash mishandling an if..then..elif..else..fi chain, which\nwas sort of unexpected for me.  I was curious but do not\nremember seeing the conclusion.  Pasky, what happened to that\nthread?\n"},{"id":"13066","messageId":"20051201215039.GX22159@pasky.or.cz","threadId":"2704","inReplyTo":"7vd5khjf9g.fsf@assigned-by-dhcp.cox.net","subject":"Re: git-name-rev off-by-one bug","fromName":"Petr Baudis","fromEmail":"pasky@suse.cz","sentAt":"2005-12-01T21:50:39Z","receivedAt":"2005-12-01T21:50:39Z","isPatch":false,"sender":{"key":"pasky@ucw.cz","avatar":"https://avatars.githubusercontent.com/u/18439?v=4"},"body":"Dear diary, on Thu, Dec 01, 2005 at 11:14:19AM CET, I got a letter\nwhere Junio C Hamano <junkio@cox.net> said that...\n> Speaking of shell gotchas, I do not know what the resolution was\n> on the problem Merlyn was having the other day in \"lost again on\n> syntax change - local repository?\" thread, which seemed that the\n> failure described in <868xv86dam.fsf@blue.stonehenge.com> was\n> his bash mishandling an if..then..elif..else..fi chain, which\n> was sort of unexpected for me.  I was curious but do not\n> remember seeing the conclusion.  Pasky, what happened to that\n> thread?\n\nI'm still perplexed and curious about what _did_ git-send-pack actually\nreceive as URL, since it apparnetly decided it's ssh as well.\n\n-- \n\t\t\t\tPetr \"Pasky\" Baudis\nStuff: http://pasky.or.cz/\nVI has two modes: the one in which it beeps and the one in which\nit doesn't.\n"},{"id":"13068","messageId":"86sltclc1p.fsf@blue.stonehenge.com","threadId":"2704","inReplyTo":"20051201215039.GX22159@pasky.or.cz","subject":"Re: git-name-rev off-by-one bug","fromName":"Randal L. Schwartz","fromEmail":"merlyn@stonehenge.com","sentAt":"2005-12-01T21:53:06Z","receivedAt":"2005-12-01T21:53:06Z","isPatch":false,"sender":{"key":"merlyn@stonehenge.com","avatar":"https://gravatar.com/avatar/dc528d210743ff0333e6213f9ee7b33b23f1b7bc1f3c5a8c2d819074ecd7ab19?d=mp&s=160"},"body":">>>>> \"Petr\" == Petr Baudis <pasky@suse.cz> writes:\n\nPetr> I'm still perplexed and curious about what _did_ git-send-pack actually\nPetr> receive as URL, since it apparnetly decided it's ssh as well.\n\nSorry... $work is swallowing my time right now.  It's on my list\nof \"very important things to get back to sometime real soon\".\n\n-- \nRandal L. Schwartz - Stonehenge Consulting Services, Inc. - +1 503 777 0095\n<merlyn@stonehenge.com> <URL:http://www.stonehenge.com/merlyn/>\nPerl/Unix/security consulting, Technical writing, Comedy, etc. etc.\nSee PerlTraining.Stonehenge.com for onsite and open-enrollment Perl training!\n"},{"id":"13093","messageId":"7v8xv39a8z.fsf@assigned-by-dhcp.cox.net","threadId":"2704","inReplyTo":"7vslte1y5z.fsf@assigned-by-dhcp.cox.net","subject":"Re: git-name-rev off-by-one bug","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2005-12-02T08:25:00Z","receivedAt":"2005-12-02T08:25:00Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Junio C Hamano <junkio@cox.net> writes:\n\n>  2. merge-one-file leaves unmerged index entries.\n>\n> Regarding #2, in an earlier message you said something about\n> \"patch to do that was just broken\" which I did not understand; I\n> think your patch I am replying to is doing the right thing.  That\n> case arm is dealing with a path that exists in \"our\" branch and\n> the working tree blob should be the same as recorded in the\n> HEAD, so I did not have to do the unpack-cat-chmod like I did in\n> mine.  Am I simply confused?\n\nThe only difference is that, from the old tradition, we are\nsupposed to allow the merge to happen in an unchecked-out\nworking tree [*1*].  The version you did and I merged in the\nmaster branch breaks that, while the patch I posted keeps that\npremise.\n\nI can throw in my change on top of what is already commited for\nnow to \"fix\" this, but do we still care about the \"merge should\nsucceed in an unchecked-out working tree\" rule, or does it not\nmatter anymore these days?\n\nOne thing is that the check with \"git diff\" to show diff between\nhalf-merged and stage2 after a failed merge does not work very\nwell in a sparsely checked out working tree, because the real\nchange is buried among tons of deletes (\"diff --diff-filter=UM\"\nhelps, though [*2*]).\n\n[Footnote]\n\n*1* ... and that is why we special case a non-existent working\ntree file as if it is clean with the index.  After a merge, you\nwould end up with a sparsely checked-out working tree that\ncontains only the files that were involved in the merge.\n\n*2* Maybe --diff-filter should always include U in the output,\nbecause it is rare and when an unmerged entry exists the user\nwould always want to see it.\n"},{"id":"13096","messageId":"7v3blb97y1.fsf_-_@assigned-by-dhcp.cox.net","threadId":"2704","inReplyTo":"7v8xv39a8z.fsf@assigned-by-dhcp.cox.net","subject":"[PATCH] merge-one-file: make sure we create the merged file.","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2005-12-02T09:14:46Z","receivedAt":"2005-12-02T09:14:46Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"The \"update-index followed by checkout-index\" chain served two\npurposes -- to collapse the index to \"our\" version, and make\nsure that file exists in the working tree.  In the recent update\nto leave the index unmerged on conflicting path, we wanted to\nstop doing the former, but we still need to do the latter (we\nallow merging to work in an un-checked-out working tree).\n\nSigned-off-by: Junio C Hamano <junkio@cox.net>\n\n---\n\n git-merge-one-file.sh |    8 +++++++-\n 1 files changed, 7 insertions(+), 1 deletions(-)\n\n7afd8d297cd0c24e51188181769b56e0fb0f4171\ndiff --git a/git-merge-one-file.sh b/git-merge-one-file.sh\nindex 9a049f4..906098d 100755\n--- a/git-merge-one-file.sh\n+++ b/git-merge-one-file.sh\n@@ -79,7 +79,13 @@ case \"${1:-.}${2:-.}${3:-.}\" in\n \t\t;;\n \tesac\n \n-\tmerge \"$4\" \"$orig\" \"$src2\"\n+\t# Create the working tree file, with the correct permission bits.\n+\t# we can not rely on the fact that our tree has the path, because\n+\t# we allow the merge to be done in an unchecked-out working tree.\n+\trm -f \"$4\" &&\n+\t\tgit-cat-file blob \"$2\" >\"$4\" &&\n+\t\tcase \"$6\" in *7??) chmod +x \"$4\" ;; esac &&\n+\t\tmerge \"$4\" \"$orig\" \"$src2\"\n \tret=$?\n \trm -f -- \"$orig\" \"$src2\"\n \n-- \n0.99.9.GIT\n"},{"id":"13098","messageId":"7vu0dr7tc8.fsf_-_@assigned-by-dhcp.cox.net","threadId":"2704","inReplyTo":"7v8xv39a8z.fsf@assigned-by-dhcp.cox.net","subject":"[PATCH] merge-one-file: make sure we do not mismerge symbolic links.","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2005-12-02T09:15:35Z","receivedAt":"2005-12-02T09:15:35Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"We ran \"merge\" command on O->A, O->B, A!=B case without verifying\nthe path involved is not a symlink.\n\nSigned-off-by: Junio C Hamano <junkio@cox.net>\n\n---\n\n git-merge-one-file.sh |    8 ++++++++\n 1 files changed, 8 insertions(+), 0 deletions(-)\n\n01655e7c9a0b05d930aa7e27e74f75e086005bfc\ndiff --git a/git-merge-one-file.sh b/git-merge-one-file.sh\nindex 906098d..c262dc6 100755\n--- a/git-merge-one-file.sh\n+++ b/git-merge-one-file.sh\n@@ -58,6 +58,14 @@ case \"${1:-.}${2:-.}${3:-.}\" in\n # Modified in both, but differently.\n #\n \"$1$2$3\" | \".$2$3\")\n+\n+\tcase \",$6,$7,\" in\n+\t*,120000,*)\n+\t\techo \"ERROR: $4: Not merging symbolic link changes.\"\n+\t\texit 1\n+\t\t;;\n+\tesac\n+\n \tsrc2=`git-unpack-file $3`\n \tcase \"$1\" in\n \t'')\n-- \n0.99.9.GIT\n"},{"id":"13097","messageId":"7vlkz37tbd.fsf_-_@assigned-by-dhcp.cox.net","threadId":"2704","inReplyTo":"7v8xv39a8z.fsf@assigned-by-dhcp.cox.net","subject":"[PATCH] git-merge documentation: conflicting merge leaves higher stages in index","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2005-12-02T09:16:06Z","receivedAt":"2005-12-02T09:16:06Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"This hopefully concludes the latest updates that changes the\nbehaviour of the merge on an unsuccessful automerge.  Instead of\ncollapsing the conflicted path in the index to show HEAD, we\nleave it unmerged, now that diff-files can compare working tree\nfiles with higher stages.\n\nSigned-off-by: Junio C Hamano <junkio@cox.net>\n\n---\n\n Documentation/git-merge.txt |   10 ++++++----\n 1 files changed, 6 insertions(+), 4 deletions(-)\n\ne8be26e9282e346b01aa41fd7ab0b5f7bf7dcfc3\ndiff --git a/Documentation/git-merge.txt b/Documentation/git-merge.txt\nindex c117404..0cac563 100644\n--- a/Documentation/git-merge.txt\n+++ b/Documentation/git-merge.txt\n@@ -108,10 +108,12 @@ When there are conflicts, these things h\n 2. Cleanly merged paths are updated both in the index file and\n    in your working tree.\n \n-3. For conflicting paths, the index file records the version\n-   from `HEAD`. The working tree files have the result of\n-   \"merge\" program; i.e. 3-way merge result with familiar\n-   conflict markers `<<< === >>>`.\n+3. For conflicting paths, the index file records up to three\n+   versions; stage1 stores the version from the common ancestor,\n+   stage2 from `HEAD`, and stage3 from the remote branch (you\n+   can inspect the stages with `git-ls-files -u`).  The working\n+   tree files have the result of \"merge\" program; i.e. 3-way\n+   merge result with familiar conflict markers `<<< === >>>`.\n \n 4. No other changes are done.  In particular, the local\n    modifications you had before you started merge will stay the\n-- \n0.99.9.GIT\n"},{"id":"13099","messageId":"20051202091946.1631.qmail@science.horizon.com","threadId":"2704","inReplyTo":"7vek4xsx49.fsf@assigned-by-dhcp.cox.net","subject":"Re: More merge questions (why doesn't this work?)","fromName":"","fromEmail":"linux@horizon.com","sentAt":"2005-12-02T09:19:46Z","receivedAt":"2005-12-02T09:19:46Z","isPatch":false,"sender":{"key":"linux@horizon.com","avatar":null},"body":"I was playing with the implications of the \"deleted file in the\nindex is not a conflict\" merge rule, and came up with the following\noctopus test which fails to work.  Note line 2 when choosing a\ndirectory to run it in!\n\n#!/bin/bash -xe\nrm -rf .git\ngit-init-db\necho \"File A\" > a\necho \"File B\" > b\necho \"File C\" > c\ngit-add a b c\ngit-commit -a -m \"Octopus test repository\"\n\ngit-checkout -b a\necho \"Modifications to a\" >> a\ngit-commit -a -m \"Modified file a\"\n\ngit-checkout -b b master\necho \"Modifications to b\" >> b\ngit-commit -a -m \"Modified file b\"\n\ngit-checkout -b c master\nrm c\ngit-commit -a -m \"Deleted file c\"\n\ngit-checkout master\n#git merge --no-commit \"\" master c b a\n#git merge --no-commit \"\" master a b c\ngit-rev-parse a b c > .git/FETCH_HEAD\ngit-octopus\n\n(Commented out are the first few things I tried.)\nCan someone tell me why this doesn't work?  It should be a simple\nin-index merge.\n\nRight after the incomplete merge (I hacked this into the\ngit-octopus script), git-ls-files -s produces\n\n100644 8fb437b77759c7709c122fbc8ba43f720e1fbc0a 0       a\n100644 b3418f25da4393974aa205e2863f012e5b503369 0       b\n100644 df78d3d51c369e1d2f1eadb73464aadd931d56b4 1       c\n100644 df78d3d51c369e1d2f1eadb73464aadd931d56b4 2       c\n\nWhich should be case 10 of the t/t1000-read-tree-m-3way.sh\ntable and succeed.\n\n\n\n\nOther things I've discovered...\n\n1) The MAJOR difference between \"git checkout\" and \"git reset --hard\"\n   are that git-checkout takes a *head* as an argument and changes the\n   .git/HEAD *symlink* to point to that head (ln -sf refs/heads/<head>\n   .git/HEAD).  \"git reset\" takes a *commit* (<rev>) as an argument and\n   changes the head that .git/HEAD points to to have that commit as its\n   hew tip (git-rev-parse <rev> > .git/HEAD)\n\n   All the other behavioural differences are relatively minor, and\n   appropriate for this big difference.\n\n2) Don't use \"git branch\" to create branches, unless you really\n   *don't* want to switch to them.  Use \"git checkout -b\".\n\n3) Dumb question: why does \"git-commit-tree\" need \"-p\" before the\n   parent commit arguments?  Isn't just argv[2]..argv[argc-1]\n   good enough?\n\n4) If the \"git-read-tree\" docs for \"--reset\", does \"ignored\" mean\n   \"not overwritten\" or \"overwritten\"?\n\n5) The final \"error\" message on \"git-merge --no-commit\" is a bit\n   alarming for a newbie who uses it because they don't quite trust\n   git's enough to enable auto-commit.  And it should be changed\n   from \"\"Automatic merge failed/prevented; fix up by hand\" to\n   \"fix up and commit by hand\".\n   Or how about:\n   \"Automatic commit prevented; edit and commit by hand.\"\n   which actually tells the truth.\n\n6) The \"pickaxe\" options are being a bit confusing, and the fact they're\n   only documented in cvs-migration.txt doesn't help.\n\n7) The git-tag man page could use a little better description of -a.\n"},{"id":"13102","messageId":"7vacfj6c4l.fsf@assigned-by-dhcp.cox.net","threadId":"2704","inReplyTo":"20051202091946.1631.qmail@science.horizon.com","subject":"Re: More merge questions (why doesn't this work?)","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2005-12-02T10:12:42Z","receivedAt":"2005-12-02T10:12:42Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"linux@horizon.com writes:\n\n> Which should be case 10 of the t/t1000-read-tree-m-3way.sh\n> table and succeed.\n\nYes.  The reason is git-read-tree's behaviour was changed\nunderneath while octopus was looking elsewhere ;-).  See\nDocumentation/technical/trivial-merge.txt, last couple of\nlines.\n\nThere are two schools of thoughts about \"both sides remove\"\n(case #10) case.  Some people argued that \"the branches might\nhave renamed that path to different paths and might indicate a\nrename/rename conflict\" (meaning read-tree should not consider\nit trivial, and leave that to upper level \"policy layer\" to\ndecide).  merge-one-file policy simply says \"no, they both\nwanted to remove them\".  If I recall correctly, read-tree itself\nmerged this case before multi-base rewrite happened (if you are\ncurious, run 'git whatchanged -p read-tree.c' and look for\n\"Rewrite read-tree\").\n\n> 1) The MAJOR difference between \"git checkout\" and \"git reset --hard\"\n\nTrue.  \"git reset --hard\" should be used without <rev> by\nnovices and with <rev> after they understand what they are\ndoing (it is used for rewinding/warping heads).\n\n> 2) Don't use \"git branch\" to create branches, unless you really\n>    *don't* want to switch to them.  Use \"git checkout -b\".\n\nBecause...?  \"git branch foo && git checkout foo\" may be\nsuboptimal to type, but it is not _wrong_; it does not do\nanything bad or incorrect.\n\n> 3) Dumb question: why does \"git-commit-tree\" need \"-p\" before the\n>    parent commit arguments?  Isn't just argv[2]..argv[argc-1]\n>    good enough?\n\n1. Why not?\n\n2. I myself wondered about it long time ago.\n\n3. It does not matter; nobody types that command by hand.\n\n4. It allows us to later add some other flags to commit-tree\n   (none planned currently).\n\n> 4) If the \"git-read-tree\" docs for \"--reset\", does \"ignored\" mean\n>    \"not overwritten\" or \"overwritten\"?\n\nThat sentence is very poorly written; a better paraphrasing is\nappreciated.\n\n\t$ git whatchanged -S--reset \\\n        \tread-tree.c Documentation/git-read-tree.txt \n\nshows logs for 438195ccedce7270cf5ba167a940c90467cb72d7 commit\n(run \"git-cat-file commit 438195cc\" to read it).  It ignores\nexisting unmerged entries when reconstructing the index from the\ngiven tree (\"git-read-tree -m\", given an unmerged index, refuses\nto operate, but \"--reset\" *ignores* the unmerged ones hence it\ndoes not refuse to operate).\n\n> 5) The final \"error\" message on \"git-merge --no-commit\" is a bit\n>    alarming for a newbie who uses it...\n\nFirst of all, --no-commit is not meant to be used by newbies,\nbut you are right.  Patches to make the failure message\nconditional are welcome.  It should switch on these three cases:\n\n - \"--no-commit\" option is given, but a merge conflict would\n   have prevented autocommit anyway;\n\n - \"--no-commit\" option is given, but automerge succeeded;\n\n - conflict prevented autocommit.\n\n> 6) The \"pickaxe\" options are being a bit confusing, and the fact they're\n>    only documented in cvs-migration.txt doesn't help.\n\nDocs of git-diff-* family have OPTIONS section, at the end of\nwhich refers you to the diffcore documentation.  Suggestions to\na better organization and a patch is appropriate here.\n\n> 7) The git-tag man page could use a little better description of -a.\n\nPlease.  It should have the same \"OPTIONS\" section as others do.\n"},{"id":"13103","messageId":"20051202113713.11618.qmail@science.horizon.com","threadId":"2704","inReplyTo":"20051202091946.1631.qmail@science.horizon.com","subject":"Re: More merge questions (why doesn't this work?)","fromName":"","fromEmail":"linux@horizon.com","sentAt":"2005-12-02T11:37:13Z","receivedAt":"2005-12-02T11:37:13Z","isPatch":false,"sender":{"key":"linux@horizon.com","avatar":null},"body":"> Yes.  The reason is git-read-tree's behaviour was changed\n> underneath while octopus was looking elsewhere ;-).  See\n> Documentation/technical/trivial-merge.txt, last couple of\n> lines.\n\n> There are two schools of thoughts about \"both sides remove\"\n> (case #10) case.\n\nUm, I'm looking at the one-side remove case, which t/t1000 calls\n\n     O       A       B         result      index requirements\n-------------------------------------------------------------------\n 10  exists  O==A    missing   remove      ditto\n ------------------------------------------------------------------\n\nwhile trivial-merge.txt says is:\n\ncase  ancest    head    remote    result\n----------------------------------------\n10    ancest^   ancest  (empty)   no merge\n\nI assumed the test case was probably more accurate, given that it's coupled\nto code which actually verifies the behaviour.\n\n> Some people argued that \"the branches might\n> have renamed that path to different paths and might indicate a\n> rename/rename conflict\" (meaning read-tree should not consider\n> it trivial, and leave that to upper level \"policy layer\" to\n> decide).  merge-one-file policy simply says \"no, they both\n> wanted to remove them\".  If I recall correctly, read-tree itself\n> merged this case before multi-base rewrite happened (if you are\n> curious, run 'git whatchanged -p read-tree.c' and look for\n> \"Rewrite read-tree\").\n\nAren't you talking about case #6?\n\n     O       A       B         result      index requirements\n-------------------------------------------------------------------\n  6  exists  missing missing   remove      must not exist.\n ------------------------------------------------------------------\n\ncase  ancest    head    remote    result\n----------------------------------------\n6     ancest+   (empty) (empty)   no merge\n\n>> 1) The MAJOR difference between \"git checkout\" and \"git reset --hard\"\n\n> True.  \"git reset --hard\" should be used without <rev> by\n> novices and with <rev> after they understand what they are\n> doing (it is used for rewinding/warping heads).\n\nFor the longest time I had been under the delusion that\n\"git-checkout <branch> *\" and \"git-reset --hard <branch>\"\nwere very similar operations (modulo your comments about\ndeleting files): overwrite the index and working directory\nfiles with the versions from that branch.\n\nIt's hard to say how much I managed to confuse myself by\ndamaging test repositories while I didn't understand what was\ngoing on.\n\n>> 2) Don't use \"git branch\" to create branches, unless you really\n>>    *don't* want to switch to them.  Use \"git checkout -b\".\n\n> Because...?  \"git branch foo && git checkout foo\" may be\n> suboptimal to type, but it is not _wrong_; it does not do\n> anything bad or incorrect.\n\nYes, I know it works.  I suggest avoiding it because there's a much\nmore convenient alternative and I kept forgetting the second half and\nchecking my changes in to the wrong branch.\n\n>> 3) Dumb question: why does \"git-commit-tree\" need \"-p\" before the\n>>    parent commit arguments?  Isn't just argv[2]..argv[argc-1]\n>>    good enough?\n\n> 1. Why not?\n> 3. It does not matter; nobody types that command by hand.\n\nBecause it's a real pain to get it properly quoted and set up\nin a shell script.  \"$@\" is a lot simpler and easier, and\nold /bin/sh only has the one array which provides that magic\nquoting behaviour.\n\n(Admittedly, you usually pass the arguments through git-rev-parse\nfirst, and are then guaranteed no embedded whitespace.)\n\n> 4. It allows us to later add some other flags to commit-tree\n>    (none planned currently).\n\nMaking it disappear wouldn't preclude having more options, either,\nany more than the variable number of arguments to cp(1) or mv(1)...\n\n>> 4) If the \"git-read-tree\" docs for \"--reset\", does \"ignored\" mean\n>>    \"not overwritten\" or \"overwritten\"?\n\n> That sentence is very poorly written; a better paraphrasing is\n> appreciated.\n\ndiff --git a/Documentation/git-read-tree.txt b/Documentation/git-read-tree.txt\nindex 8b91847..47e2f93 100644\n--- a/Documentation/git-read-tree.txt\n+++ b/Documentation/git-read-tree.txt\n@@ -31,8 +31,8 @@ OPTIONS\n \tPerform a merge, not just a read.\n \n --reset::\n-\n-        Same as -m except that unmerged entries will be silently ignored.\n+        Same as -m except that unmerged entries will be silently overwritten\n+\t(instead of failing).\n \n -u::\n \tAfter a successful merge, update the files in the work\n@@ -47,7 +47,6 @@ OPTIONS\n \ttrees that are not directly related to the current\n \tworking tree status into a temporary index file.\n \n-\n <tree-ish#>::\n \tThe id of the tree object(s) to be read/merged.\n \n\n>> 5) The final \"error\" message on \"git-merge --no-commit\" is a bit\n>>    alarming for a newbie who uses it...\n\n> First of all, --no-commit is not meant to be used by newbies,\n> but you are right.\n\nWell, I can tell you that it's very very attractive to newbies.\nThe first 5 or 10 times I tried git-merge, I used --no-commit.\n(My surprise was mostly that there wasn't a one-letter -x form.)\n\"Do something really complicated and then commit it to the repository\"\nis a frightening concept.  \"Do something really complicated and\nthen stop and wait for you to see if it was what you expected\" is\na lot more comforting.\n\n>> 6) The \"pickaxe\" options are being a bit confusing, and the fact they're\n>>    only documented in cvs-migration.txt doesn't help.\n\n> Docs of git-diff-* family have OPTIONS section, at the end of\n> which refers you to the diffcore documentation.  Suggestions to\n> a better organization and a patch is appropriate here.\n\nThat's a bigger job; I'll work on it when I've finished the docs I'm\nwriting right. :-)\n\n>> 7) The git-tag man page could use a little better description of -a.\n\n> Please.  It should have the same \"OPTIONS\" section as others do.\n\nI know NOTHING about asciidoc, and really wish I could fix its\nlack-of-line-break problem:\n\nGIT-BISECT(1)                                                    GIT-BISECT(1)\n\nNAME\n       git-bisect - Find the change that introduced a bug\n\nSYNOPSIS\n       git  bisect start git bisect bad <rev> git bisect good <rev> git bisect\n       reset [<branch>] git bisect visualize git bisect replay  <logfile>  git\n       bisect log\n\nbut emulating what I saw elsewhere...\n\ndiff --git a/Documentation/git-tag.txt b/Documentation/git-tag.txt\nindex 95de436..7635b1e 100644\n--- a/Documentation/git-tag.txt\n+++ b/Documentation/git-tag.txt\n@@ -10,6 +10,26 @@ SYNOPSIS\n --------\n 'git-tag' [-a | -s | -u <key-id>] [-f | -d] [-m <msg>] <name> [<head>]\n \n+OPTIONS\n+-------\n+-a::\n+\tMake an unsigned (anotation) tag object\n+\n+-s::\n+\tMake a GPG-signed tag, using the default e-mail address's key\n+\n+-u <key-id>::\n+\tMake a GPG-signed tag, using the given key\n+\n+-f::\n+\tReplace an existing tag with the given name (instead of failing)\n+\n+-d::\n+\tDelete an existing tag with the given name\n+\n+-m <msg>::\n+\tUse the given tag message (instead of prompting)\n+\n DESCRIPTION\n -----------\n Adds a 'tag' reference in .git/refs/tags/\n@@ -23,7 +43,7 @@ creates a 'tag' object, and requires the\n in the tag message.\n \n Otherwise just the SHA1 object name of the commit object is\n-written (i.e. an lightweight tag).\n+written (i.e. a lightweight tag).\n \n A GnuPG signed tag object will be created when `-s` or `-u\n <key-id>` is used.  When `-u <key-id>` is not used, the\n"},{"id":"13105","messageId":"20051202130911.GY8383MdfPADPa@greensroom.kotnet.org","threadId":"2704","inReplyTo":"7vacfj6c4l.fsf@assigned-by-dhcp.cox.net","subject":"Re: More merge questions (why doesn't this work?)","fromName":"Sven Verdoolaege","fromEmail":"skimo@kotnet.org","sentAt":"2005-12-02T13:09:12Z","receivedAt":"2005-12-02T13:09:12Z","isPatch":false,"sender":{"key":"skimo@kotnet.org","avatar":null},"body":"On Fri, Dec 02, 2005 at 02:12:42AM -0800, Junio C Hamano wrote:\n> linux@horizon.com writes:\n> > 3) Dumb question: why does \"git-commit-tree\" need \"-p\" before the\n> >    parent commit arguments?  Isn't just argv[2]..argv[argc-1]\n> >    good enough?\n> \n> 3. It does not matter; nobody types that command by hand.\n> \n\nI do.  git commit won't let me commit an empty tree, or at\nleast I haven't figured out how to make it do that.\n\nI also used it when, after resolving a merge initiated by\ncg-merge, cogito (or at least the version I had installed\nat the time) wouldn't let me commit it because a new file\nI had pulled in contained non-ascii characters in its name.\n\nskimo\n"},{"id":"13112","messageId":"7vbqzz2qc8.fsf@assigned-by-dhcp.cox.net","threadId":"2704","inReplyTo":"20051202113713.11618.qmail@science.horizon.com","subject":"Re: More merge questions (why doesn't this work?)","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2005-12-02T20:31:35Z","receivedAt":"2005-12-02T20:31:35Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"linux@horizon.com writes:\n\n> Um, I'm looking at the one-side remove case, which t/t1000 calls\n>\n>      O       A       B         result      index requirements\n> -------------------------------------------------------------------\n>  10  exists  O==A    missing   remove      ditto\n>  ------------------------------------------------------------------\n>\n> while trivial-merge.txt says is:\n>\n> case  ancest    head    remote    result\n> ----------------------------------------\n> 10    ancest^   ancest  (empty)   no merge\n>\n> I assumed the test case was probably more accurate, given that it's coupled\n> to code which actually verifies the behaviour.\n\nYou are right.  And the test expects something different from\nthat table in t/t1000 test.  Relevant are the lines for ND (one\nside No action the other Delete) in the \"expected\" file.  The\ntest expects the result to be unmerged.\n\nInteresting is that it did so from the day one [*1*].  The very\noriginal read-tree 3-way was quite conservative and left more\nthings unmerged for the policy script to handle, and it is not\nsurprising it started like this, but during the course of the\nproject I thought read-tree was made to collapse more cases in\nindex.  I am a bit surprised we did not loosen it ever since\n[*2*].  Thanks for pointing out the discrepancy.\n\nWe earlier agreed that the table in t/t1000 test should go and\nsuperseded by trivial-merge.txt, so what the table says right\nnow is a non-issue, but we _might_ want to revisit the issue of\nwhat should happen in case #8 and #10 sometime in the future, as\nthe last three lines of trivial-merge.txt mentions.  I'd say we\nshould leave things as they are for now, though.\n\n>  --reset::\n> -\n> -        Same as -m except that unmerged entries will be silently ignored.\n> +        Same as -m except that unmerged entries will be silently overwritten\n> +\t(instead of failing).\n\nThanks.\n\n> \"Do something really complicated and then commit it to the repository\"\n> is a frightening concept.  \"Do something really complicated and\n> then stop and wait for you to see if it was what you expected\" is\n> a lot more comforting.\n\nFair enough.\n\n>>> 7) The git-tag man page could use a little better description of -a.\n>\n>> Please.  It should have the same \"OPTIONS\" section as others do.\n>\n> I know NOTHING about asciidoc, and really wish I could fix its\n> lack-of-line-break problem:\n\nThanks for pointing that one ont.  I think Josef recently did\nsimilar linebreak on git-mv page.  I'll try and see if I can\nmimic what he did [*3*].\n\n> diff --git a/Documentation/git-tag.txt b/Documentation/git-tag.txt\n> index 95de436..7635b1e 100644\n> --- a/Documentation/git-tag.txt\n> +++ b/Documentation/git-tag.txt\n\nThanks; applied.  \n\n[Footnotes]\n\n*1* A pickaxe example:\n\n\t$ git whatchanged -p -S'100644 1 ND\n          100644 2 ND'\n\nshows only two commits.  One is the first version of the test,\nand the other is to adjust for the output format from \n\n*2* Further archaeology revealed that I did loosening primarily\nfor the 2-way side, and did not touch much about 3-way merge\nother than what used to be marked with ALT.  There was no 10ALT\never so it shows that my memory is simply faulty ;-).\n\n*3* I did that, and it renders HTML side nicer, but it breaks\nmanpages X-<.  Inputs from asciidoc gurus are appreciated.\n"},{"id":"13113","messageId":"7v4q5r2qb2.fsf@assigned-by-dhcp.cox.net","threadId":"2704","inReplyTo":"20051202130911.GY8383MdfPADPa@greensroom.kotnet.org","subject":"Re: More merge questions (why doesn't this work?)","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2005-12-02T20:32:17Z","receivedAt":"2005-12-02T20:32:17Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Sven Verdoolaege <skimo@kotnet.org> writes:\n\n>> 3. It does not matter; nobody types that command by hand.\n\nI should have said \"nobody should need to type that, otherwise\nfix your Porcelain\".\n\n> I do.  git commit won't let me commit an empty tree, or at\n> least I haven't figured out how to make it do that.\n\nYou are right, at least for the initial commit (for subsequent\ncommits it happily commits an empty tree).\n\nNow why anybody would want to it is a different matter.  Is it\nbecause you would want to record that your project started from\nscratch, as opposed to some import from an existing non\nversioned (or versioned by another SCM) working tree?\n\n> I also used it when, after resolving a merge initiated by\n> cg-merge, cogito (or at least the version I had installed\n> at the time) wouldn't let me commit it because a new file\n> I had pulled in contained non-ascii characters in its name.\n\nThat sounds like a simple Porcelain bug and I hope neither\nCogito or git wouldn't have that problem now.\n"},{"id":"13116","messageId":"20051202213214.27282.qmail@science.horizon.com","threadId":"2704","inReplyTo":"7vbqzz2qc8.fsf@assigned-by-dhcp.cox.net","subject":"Re: More merge questions (why doesn't this work?)","fromName":"","fromEmail":"linux@horizon.com","sentAt":"2005-12-02T21:32:14Z","receivedAt":"2005-12-02T21:32:14Z","isPatch":false,"sender":{"key":"linux@horizon.com","avatar":null},"body":"> We earlier agreed that the table in t/t1000 test should go and\n> superseded by trivial-merge.txt, so what the table says right\n> now is a non-issue, but we _might_ want to revisit the issue of\n> what should happen in case #8 and #10 sometime in the future, as\n> the last three lines of trivial-merge.txt mentions.  I'd say we\n> should leave things as they are for now, though.\n\nBut back to my original problem... I don't much care whether it's\ndone as a trivial merge or a non-trivial merge, but why the #%@#$ can't\nit be done as an automatic merge?\n\nAs I said, I'm trying to build (and write down) a mental model, so the\nbehaviour of git can be predicted.  My mental model says this should\nwork.  It doesn't.  Therefore my mental model is incorrect, and I\ndon't actually understand what it's doing.\n\n#!/bin/bash -xe\nrm -rf .git\ngit-init-db\necho \"File A\" > a\necho \"File B\" > b\necho \"File C\" > c\ngit-add a b c\ngit-commit -a -m \"Octopus test repository\"\n\ngit-checkout -b a\necho \"Modifications to a\" >> a\ngit-commit -a -m \"Modified file a\"\n\ngit-checkout -b b master\necho \"Modifications to b\" >> b\ngit-commit -a -m \"Modified file b\"\n\ngit-checkout -b c master\nrm c\ngit-commit -a -m \"Deleted file c\"\n\ngit-checkout master\ngit merge \"Merge a, b, c\" master a b c\n\nproduces...\n\n+ git merge 'Merge a, b, c' master a b c\nTrying simple merge with a\nTrying simple merge with b\nTrying simple merge with c\nSimple merge did not work, trying automatic merge.\nRemoving c\nfatal: merge program failed\nNo merge strategy handled the merge.\n\n\n> *3* I did that, and it renders HTML side nicer, but it breaks\n> manpages X-<.  Inputs from asciidoc gurus are appreciated.\n\nI tried adding \" +\" at end-of-line, which is supposed to force a\nline break, but that didn't have any effect.\n"},{"id":"13118","messageId":"20051202215658.1731.qmail@science.horizon.com","threadId":"2704","inReplyTo":"7vbqzz2qc8.fsf@assigned-by-dhcp.cox.net","subject":"Re: More merge questions","fromName":"","fromEmail":"linux@horizon.com","sentAt":"2005-12-02T21:56:58Z","receivedAt":"2005-12-02T21:56:58Z","isPatch":false,"sender":{"key":"linux@horizon.com","avatar":null},"body":"Just thinking about the difference between 2-way and 3-way merge...\n\n*Mostly* a 2-way merge is just a 3-way merge where one of the ways\nis taken from the index rather than from a tree.  But there\nare some subtle differences.\n\nThis diffierence is what forces octopus merge to form intermediate tree\nobjects when doing its merges.  If there was a way to merge directly\ninto the index, octopus merge wouldn't have to make intermediate tree\nobjects that would have to be garbage-collected later.\n\n(Indeed, I originally assumed that Octopus did all its merges in the\nindex; it's only when I traced the code that I saw it calls git-write-tree\nmultiple times.)\n\nIs the time saved, and space not wasted, worth implementing a 2-way merge\nthat more exactly matches 3-way?  It should be fairly straightforward\nto share the actual merging code.\n\nOpinions solicited.\n"},{"id":"13119","messageId":"loom.20051202T225802-582@post.gmane.org","threadId":"2704","inReplyTo":"20051202213214.27282.qmail@science.horizon.com","subject":"Re: More merge questions (why doesn't this work?)","fromName":"Junio C Hamano","fromEmail":"junkio@twinsun.com","sentAt":"2005-12-02T22:00:42Z","receivedAt":"2005-12-02T22:00:42Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":" <linux <at> horizon.com> writes:\n\n> + git merge 'Merge a, b, c' master a b c\n> Trying simple merge with a\n> Trying simple merge with b\n> Trying simple merge with c\n> Simple merge did not work, trying automatic merge.\n> Removing c\n> fatal: merge program failed\n> No merge strategy handled the merge.\n\nI think this is the same problem I fixed yesterday after the breakage report\nfrom Luben Tuikov.  You need the ce3ca275452cf069eb6451d6f5b0f424a6f046aa commit.\nSorry about that.\n\nCould you try the latest and see if it still breaks?\n"},{"id":"13121","messageId":"Pine.LNX.4.64.0512021409320.3099@g5.osdl.org","threadId":"2704","inReplyTo":"20051202213214.27282.qmail@science.horizon.com","subject":"Re: More merge questions (why doesn't this work?)","fromName":"Linus Torvalds","fromEmail":"torvalds@osdl.org","sentAt":"2005-12-02T22:12:57Z","receivedAt":"2005-12-02T22:12:57Z","isPatch":false,"sender":{"key":"torvalds@linux-foundation.org","avatar":"https://avatars.githubusercontent.com/u/1024025?v=4"},"body":"\n\nOn Fri, 2 Dec 2005, linux@horizon.com wrote:\n>\n> produces...\n> \n> + git merge 'Merge a, b, c' master a b c\n> Trying simple merge with a\n> Trying simple merge with b\n> Trying simple merge with c\n> Simple merge did not work, trying automatic merge.\n> Removing c\n> fatal: merge program failed\n> No merge strategy handled the merge.\n\nI'm getting\n\n\t...\n\t+ git merge 'Merge a, b, c' master a b c\n\tTrying simple merge with a\n\tTrying simple merge with b\n\tTrying simple merge with c\n\tSimple merge did not work, trying automatic merge.\n\tRemoving c\n\tMerge 9ca217790c7e6581fe0b8b3b4baf026d03584c66, made by octopus.\n\t a |    1 +\n\t b |    1 +\n\t c |    1 -\n\t 3 files changed, 2 insertions(+), 1 deletions(-)\n\t delete mode 100644 c\n\nand I don't see why you wouldn't get that too.\n\nDo you have that broken version of git that had problems with \"rmdir\" and \nthought the unlink failed? \n\n\t\tLinus\n"},{"id":"13125","messageId":"20051202231450.11116.qmail@science.horizon.com","threadId":"2704","inReplyTo":"Pine.LNX.4.64.0512021409320.3099@g5.osdl.org","subject":"Re: More merge questions (why doesn't this work?)","fromName":"","fromEmail":"linux@horizon.com","sentAt":"2005-12-02T23:14:50Z","receivedAt":"2005-12-02T23:14:50Z","isPatch":false,"sender":{"key":"linux@horizon.com","avatar":null},"body":"> and I don't see why you wouldn't get that too.\n> \n> Do you have that broken version of git that had problems with \"rmdir\" and \n> thought the unlink failed? \n\nQuite possibly; my previous version of git was 27 November.\n(I've been using the Debian package builder, which insists on a\nfull rebuild each time and is thus annoyingly slow... especially\nthe \"xmlto man\" part.  I think I'll switch to \"make; make install\")\n\nAnyway, updated and it works as expected.  Sorry for the spurious\ncomplaint.\n"},{"id":"13181","messageId":"20051204213458.GY22159@pasky.or.cz","threadId":"2704","inReplyTo":"7vhd9vgumb.fsf@assigned-by-dhcp.cox.net","subject":"Re: git-name-rev off-by-one bug","fromName":"Petr Baudis","fromEmail":"pasky@suse.cz","sentAt":"2005-12-04T21:34:58Z","receivedAt":"2005-12-04T21:34:58Z","isPatch":false,"sender":{"key":"pasky@ucw.cz","avatar":"https://avatars.githubusercontent.com/u/18439?v=4"},"body":"Dear diary, on Tue, Nov 29, 2005 at 07:46:20PM CET, I got a letter\nwhere Junio C Hamano <junkio@cox.net> said that...\n> Petr Baudis <pasky@suse.cz> writes:\n> \n> >   (ii) Cogito will handle trees with some local modifications better -\n> > basically any local modifications git-read-tree -m won't care about.\n> > I didn't read the whole conversation, so to reiterate: git-read-tree\n> > will complain when the index does not match the HEAD, but won't\n> > complain about modified files in the working tree if the merge is not\n> > going to touch them. Now, let's say you do this (output is visually\n> > only roughly or not at all resembling what would real tools tell you):\n> >\n> > \t$ ls\n> > \ta b c\n> > \t$ echo 'somelocalhack' >>a\n> > \t$ git merge \"blah\" HEAD remotehead\n> > \tFile-level merge of 'b' and 'c'...\n> > \tOops, 'b' contained local conflicts.\n> > \tAutomatic merge aborted, fix up by hand.\n> > \t$ fixup b\n> > \t$ git commit\n> > \tCommitted files 'a', 'b', 'c'.\n> >\n> > Oops. It grabbed your local hack and committed it along the merge.\n> \n> Are you sure about this?\n> \n> In the above sequence, after you touch a with 'somelocalhack',\n> there is no 'git update-index a', until you say 'git commit'\n> there, so I do not think that mixup is possible.\n> \n> The \"fixup b\" step is actually two commands, so after merge\n> command, you would do:\n> \n>         $ edit b\n> \t$ git update-index b ;# mark that you are dealt with it\n> \t$ git commit ;# commits what is in index\n> \n> After the above steps, \"git diff\" (that is working tree against\n> index) still reports your local change to \"a\", which were _not_\n> committed.\n\nYes. I actually tried it out, but I was confused by the file list in the\ncommit message (I'm used to seeing just committed files there) and I\ndidn't check the status of the 'a' file after the commit.\n\nSorry about the confusion.\n\n-- \n\t\t\t\tPetr \"Pasky\" Baudis\nStuff: http://pasky.or.cz/\nVI has two modes: the one in which it beeps and the one in which\nit doesn't.\n"},{"id":"13204","messageId":"20051205150145.GA30765MdfPADPa@greensroom.kotnet.org","threadId":"2704","inReplyTo":"7v4q5r2qb2.fsf@assigned-by-dhcp.cox.net","subject":"Re: More merge questions (why doesn't this work?)","fromName":"Sven Verdoolaege","fromEmail":"skimo@kotnet.org","sentAt":"2005-12-05T15:01:45Z","receivedAt":"2005-12-05T15:01:45Z","isPatch":false,"sender":{"key":"skimo@kotnet.org","avatar":null},"body":"On Fri, Dec 02, 2005 at 12:32:17PM -0800, Junio C Hamano wrote:\n> Sven Verdoolaege <skimo@kotnet.org> writes:\n> > I do.  git commit won't let me commit an empty tree, or at\n> > least I haven't figured out how to make it do that.\n> \n> You are right, at least for the initial commit (for subsequent\n> commits it happily commits an empty tree).\n> \n> Now why anybody would want to it is a different matter.  Is it\n> because you would want to record that your project started from\n> scratch, as opposed to some import from an existing non\n> versioned (or versioned by another SCM) working tree?\n\nSomething like that, yes.\n\nIn the beginning there as nothing and git commited the nothingness.\n\nskimo\n"},{"id":"13349","messageId":"20051208063409.31967.qmail@science.horizon.com","threadId":"2704","inReplyTo":"20051204213458.GY22159@pasky.or.cz","subject":"as promised, docs: git for the confused","fromName":"","fromEmail":"linux@horizon.com","sentAt":"2005-12-08T06:34:09Z","receivedAt":"2005-12-08T06:34:09Z","isPatch":false,"sender":{"key":"linux@horizon.com","avatar":null},"body":"As I mentioned with all my questions, I was writing up the answers\nI got.  Here's the current status.  If anyone would like to comment on\nits accuracy or usefulness, feedback is appreciated.\n\nI've tried to omit or skim very lightly over subjects I think\nare adequately explained in existing docs, unless that would\nleave an uncomfortable hole in the explanation.\n\nTODO: Describe the config file.  It's a recent invention, and I\nhaven't found a good description of its contents.\n\n\n\t\t\"I Don't Git It\"\n\t\tGit for the confused\n\nGit is hardly lacking in documentation, but coming at it fresh, I found\nit somewhat confusing.\n\nGit is a toolkit in the Unix tradition.  There are a number of primitives\nwritten in C, which are made friendly by a layer of shell scripts.\nThese are known in git-speak, as the \"plumbing\" and the \"porcelain\",\nrespectively.  The porcelain should work and look nice.  The plumbing\nshould just deal with lots of crap efficiently.\n\nMuch of git's documentation was first written to explain the plumbing to\nthe people writing the porcelain.  Since then, although the essentials\nhaven't changed, porcelain has been added and conventions have been\nestablished that make it a lot more pleasant to deal with.  Some commands\nhave been changed or replaced, and it's not quite the same.\n\nUsing the original low-level commands is now most likely more difficult\nthan necessary, unless you want to do something not supported by the\nexisting porcelain.\n\nThis document retraces (with fewer false turns) how I learned my\nway around git.  There are some concepts I didn't understand so well\nthe first time through, and an overview of all the git commands, grouped\nby application.\n\n\nA good rule of thumb is that the commands with one-word names (git-diff,\ngit-commit, git-merge, git-push, git-pull, git-status, git-tag, etc.) are\ndesigned for end-user use.  Multi-word names (git-count-objects,\ngit-write-tree, git-cat-file) are generally designed for use from\na script.\n\nThis isn't ironclad.  The first command to start using git is git-init-db,\nand git-show-branch is pure porcelain, while git-mktag is a primitive.\nAnd you don't often run git-daemon by hand.  But still, it's a useful\nguideline.\n\n\n* Background material.\n\nTo start with, read \"man git\".  Or Documentation/git.txt in the git\nsource tree, which is the same thing.  Particularly note the description\nof the index, which is where all the action in git happens.\n\nOne thing that's confusing is why git allows you to have one version of\na file in the current HEAD, a second version in the index, and possibly a\nthird in the working directory.  Why doesn't the index just contain a copy\nof the current HEAD until you commit a new one?  The answer is merging,\nwhich does all its work in the index.  Neither the object database nor\nthe working directory let you have multiple files with the same name.\n\nThe index is really very simple.  It's a series of structures, each\ndescribing one file.  There's an object ID (SHA1) of the contents,\nsome file metadata to detect changes (time-stamps, inode number, size,\npermissions, owner, etc.), and the path name relative to the root of\nthe working directory.  It's always stored sorted by path name, for\nefficient merging.\n\nAt (almost) any time, you can take a snapshot of the index and write\nit as a tree object.\n\nThe only interesting feature is that each entry has a 2-bit stage number.\nNormally, this is always zero, but each path name is allowed up to three\ndifferent versions (object IDs) in the index at once.  This is used to\nrepresent an incomplete merge, and an unmerged index entry (with more\nthan one version) prevents committing the index to the object database.\n\n\n* Terminology - heads, branches, refs, and revisions\n\n(This is a supplement to what's already in \"man git\".)\n\nThe most common object needed by git primitives is a tree.  Since a\ncommit points to a tree and a tag points to a commit, both of these are\nacceptable \"tree-ish\" objects and can be used interchangeably.  Likewise,\na tag is \"commit-ish\" and can be used where a commit is required.\n\nAs soon as you get to the porcelain, the most commonly used object is\na commit.  Also known as a revision, this is a tree plus a history.\n\nWhile you can always use the full object ID, you can also use a reference.\nA reference is a file that contains a 40-character hex SHA1 object ID\n(and a trailing newline).  When you specify the name of a reference,\nit is searched for in one of the directories:\n\t.git/\t\t\t(or $GIT_DIR)\n\t.git/refs/\t\t(or $GIT_DIR/refs/)\n\t.git/refs/heads/\t(or $GIT_DIR/refs/heads/)\n\t.git/refs/tags/\t\t(or $GIT_DIR/refs/tags/)\n\nYou may use subdirectories by including slashes in the reference name.\nThere is no search order; if searching the above four path prefixes\nproduces more than one match for the reference name (it's ambiguous),\nthen the name is not valid.\n\nThere is additional syntax (which looks like \"commit~3^2~17\") for\nspecifying an ancestor of a given commit (or tag).  This is documented\nin detail in the documentation for git-rev-parse.  Briefly, commit^\nis the parent of the given commit.  commit^^ is the grandparent, etc..\nIf there is more than one ancestor (a merge), then they can be referenced\nas commit^1 (a synonym for commit^), commit^2, commit^3, etc.  (commit^0\ngives the commit object itself.  A no-op if you're starting from a commit,\nbut it lets you get the commit object from a tag object.)\n\nAs long strings of ^ can be annoying, they can be abbreviated using ~\nsyntax.  commit^^^ is the same as commit~3, ^^^^ is the same as ~4, etc.\nYou can see lots of examples in the output of \"git-show-branch\".\n\n\nNow, the although the most primitive git tools don't care, a convention\namong all the porcelain is that the current head of development is\n.git/HEAD, a symbolic link to a reference under refs/heads/.\n\ngit-init-db creates HEAD pointing to refs/heads/master, and that is\ntraditionally the name used for the \"main trunk\" of development.\nNote that initially refs/heads/master doesn't exist - HEAD is a\ndangling symlink!  This is okay, and will cause the initial commit\nto have zero parents.\n\nA \"head\" is mostly synonymous with a \"branch\", but the terms have\ndifferent emphasis.  The \"head\" is particularly the tip of the branch,\nwhere future development will be appended.  A \"branch\" is the entire\ndevelopment history leading to the head.  However, as far as git is\nconcerned, they're both references to commit objects, referred to from\nrefs/heads/.\n\nWhen you actually do more (with git-commit, or git-merge), then the\ncurrent HEAD reference is overwritten with the new commit's id, and\nthe old HEAD becomes HEAD^.  Since HEAD is a symlink, it's the file\nin refs/heads/ that's actually overwritten.  (See the git-update-ref\ndocumentation for further details.)\n\nThe git-checkout command actually changes the HEAD symlink.  git-checkout\nenforces the rule that it will only check out a branch under refs/heads.\nYou can use refs/tags as a source for git-diff or any other command that\nonly examines the revision, but if you want to check it out, you have\nto copy it to refs/heads.\n\n\n* Resetting\n\nThe \"undo\" command for commits to the object database is git-reset.\nLike all deletion-type commands, be careful or you'll hurt yourself.\nGiven a commit (using any of the syntaxes mentioned above), this\nsets the current HEAD to refer to the given commit.\n\nThis does NOT alter the HEAD symlink (as git-checkout <branch> will\ndo), but actually changes the reference pointed to by HEAD\n(e.g. refs/heads/master) to contain a new object ID.\n\nThe classic example is to undo an erroneous commit, use\n\"git-reset HEAD^\".\n\nThere are actually three kinds of git-reset:\ngit-reset --soft: Only overwrite the reference.  If you can find the\n\told object ID, you can put everything back with a second\n\tgit-reset --soft OLD_HEAD.\ngit-reset --mixed: This is the default, which I always think of\n\tas \"--medium\".  Overwrite the reference, and (using\n\tgit-read-tree) read the commit into the index.  The\n\tworking directory is unchanged.\ngit-reset --hard: Do everything --mixed does, and also check out\n\tthe index into the working directory.  This really erases\n\tall traces of the previous version.  (One caveat: this\n\twill not delete any files in the working directory that\n\twere added as part of the changes being undone.)\n\nThe space taken up by the abandoned commit won't actually be\nreclaimed until you collect garbage with git-prune.\n\ngit-reset with no commit specified is \"git-reset HEAD\", which is much\nsafer because the object reference is not actually changed.  This can\nbe used to undo changes in the index or working directory that you did\nnot intend.  Note, however, that it is not selective.  \"git-commit\"\nhas options for doing this selectively.\n\nLike being sure what directory you're in when typing \"rm -r\", think\ncarefully about what branch you're on when typing \"git-reset <commit>\".\n\nThere is an undelete: git-reset stores the previous HEAD commit\nin OLD_HEAD.  And git-lost-found can find leftover commits\nuntil you do a git-prune.\n\n\n* Merging\n\nMerging is central to git operations.  Indeed, a big difference between\ngit and other version control systems is that git assumes that a change\nwill be merged more often than it's written, as it's passed around\ndifferent developers' repositories.  Even \"git checkout\" is a merge.\n\nThe heart of merging is git-read-tree, but if you can understand it from\nthe man page, you're doing better than me.\n\nAs mentioned, the index and the working directory versions of a file\ncould both be different from the HEAD.  Git lets you merge \"under\" your\ncurrent working directory edits, as long as the merge doesn't change\nthe files you're editing.\n\nThere are some special cases of merging, but let me start with the\nprocedure for the general 3-way merge case: merging branch B into branch A\n(the current HEAD).\n\n1) Given two commits, find a common ancestor O to server as the origin\n   of the merge.  The basic \"resolve\" algorithm uses git-merge-base for\n   the task, but the \"recursive\" merge strategy gets more clever in the\n   case where there are multiple candidates.  I won't got into what it\n   does, but it does a pretty good job.\n\n2) Add all three input trees (the Origin, A, and B) to the index by\n   \"git-read-tree -m O A B\".  The index now contains up to three copies\n   of every file.  (Four, including the original, but that is discarded\n   before git-read-tree returns.)\n\n   Then, for each file in the index, git-read-tree does the following:\n\n   2a) For each file, git-merge-tree tries to collapse the various\n       versions into one using the \"trivial in-index merge\".  This just\n       uses the file blob object names to see if the file contents\n       are identical, and if two or more of the three trees contain an\n       identical copy of this file, it is merged.  A missing (deleted)\n       file matches another missing file.\n\n       Note that this is NOT a majority vote.  If A and B agree on the\n       contents of the file, that's what is used.  (Whether O agrees is\n       irrelevant in this case.)  But if O and A agree, then the change\n       made in B is taken as the final value.  Likewise, if O and B agree,\n       then A is used.\n\n   2b) If this is possible, then a check is made to see if the merge would\n       conflict with any uncommitted work in the index or change the index\n       out from under a modified working directory file.  If either of\n       those cases happen, the entire merge is backed out and fails.\n\n       (In the git source, the test \"t/t1000-read-tree-m-3way.sh\" has\n       a particularly detailed description of the various cases.)\n\n       If the merge is possible and safe, the versions are collapsed\n       into one final result version.\n\n   2c) If all three versions differ, the trivial in-index merge is\n       not possible, and the three source versions are left in the\n       index unmerged.  Again, if there was uncommitted work in the\n       index or the working directory, the entire merge fails.\n\n3) Use git-merge-index to iterate over the remaining unmerged files, and\n   apply an intra-file merge.  The intra-file merge is usually done with\n   git-merge-one-file, which does a standard RCS-style three-way merge\n   (see \"man merge\").\n\n4) Check out all the successfully merged files into the working directory.\n\n5) If automatic merging was successful on every file, commit the merged\n   version immediately and stop.\n\n6) If automatic merging was not complete, then replace the working\n   directory copies of any remaining unmerged files with a merged copy\n   with conflict markers (again, just like RCS or CVS) in the working\n   directory.  All three source versions are available in the index for\n   diffing against.\n\n   (We have not destroyed anything, because in step 2c), we checked to make\n   sure the working directory file didn't have anything not in the\n   repository.)\n\n7) Manually edit the conflicts and resolve the merge.  As long as an\n   unmerged, multi-version file exists in the index, committing the\n   index is forbidden.  (You can use the options to git-diff to\n   see the changes.)\n\n8) Commit the final merged version of the conflicting file(s), replacing\n   the unmerged versions with the single finished version.\n\nNote that if the merge is simple, with no one file edited on both\nbranches, git never has to open a single file.  It reads three tree\nobjects (recursively) and stat(2)s some working directory files to\nverify that they haven't changed.\n\nAlso note that this aborts and backs out rather than overwrite\nanything not committed.  You can merge \"under\" uncommitted edits\nonly if those edits are to files not affected by the merge.\n\n\n* 2-way merging\n\nA \"2-way merge\" is basically a 3-way merge with the contents of the\nindex as the \"current HEAD\", and the original HEAD as the Origin.\nHowever, this merge is designed only for simple cases and only supports\nthe \"trivial merge\" cases.  It does not fall back to an intra-file merge.\n\n[[ I'm not sure why it couldn't, I confess.  For reversibility?  Or\njust because it's likely to be too confusing.  ]]\n\nThis merge is used by git-checkout to switch between two branches,\nwhile preserving any changes in the working directory and index.\n\nLike the 3-way case, if a particular file hasn't changed between\nthe two heads, then git will preserve any uncommitted edits.\nIf the file has changed in any way, git doesn't try to perform\nany sort of intra-file merge, it just fails.\n\n* 1-way merging\n\nThis is not actually used by the git-core porcelain, and so is only\nuseful to someone writing more porcelain, but I'll describe it for\ncompleteness.\n\nPlain (non-merging) git-read-tree will overwrite the index entries with\nthose from the tree.  This invalidates the cached stat data, causing\ngit to think all the working directory files are \"potentially changed\"\nuntil you do a git-update-index --refresh.\n\nBy specifying a 1-way merge, any index entry whose contents (object ID)\nmatches the incoming tree will have its cached stat data preserved.\nThus, git will know if the working directory file is not changed, and\nwill not overwrite if you execute git-checkout-index.\n\nThis is purely an efficiency hack.\n\n\n* Special merges - already up to date, and fast-forward\n\nThere are two cases of 3-way or 2-way merging that are special.\nRecall that the basic merge pattern is\n\n   B--------> A+B\n  /        /\n /        /\nO -----> A\n\nThe two special cases arise if one of A or B is a direct ancestor of\nthe other.  In that case, the common ancestor of both A and B is the\nolder of the two commits.  And the merged result is simply the\nnewer of the two, unchanged.\n\nRecalling that we are merging B into A, if B is a direct ancestor of A,\nthen A already includes all of B.  A is \"already up to date\" and not\nchanged at all by the merge.\n\nThe other case you'll hear mentioned, because it happens a lot when\npulling, is when A is a direct ancestor of B.  In this case, the\nresult of the merge is a \"fast-forward\" to B.\n\nBoth of these cases are handled very efficiently by the in-index merge\ndone by git-read-tree.\n\n\n* Deleted files during merges\n\nThere is one small wrinkle in git's merge algorithm that will probably\nnever bite you, but I ought to explain anyway, just because it's so rare\nthat it's difficult to discover it by experiment.\n\nThe index contains a list of all files that git is tracking.  If the\nindex file is empty or missing and you do a commit, you write an empty\ntree with no files.\n\nWhen merging, if git finds no pre-existing index entry for a path it is\ntrying to merge, it considers that to mean \"status unknown\" rather than\n\"modified by being deleted\".  Thus, this is not uncommitted work\nin the index file, and does not block the merge.  Instead, the\nfile will reappear in the merge.\n\nThis is because it is possible to blow away the index file (rm .git/index\nwill do it quite nicely), and if this was considered a modification to\nbe preserved, it would cause all sorts of conflicts.\n\nSo the one change to the index that will NOT be preserved by a merge is\nthe removal of a file.  A missing index entry is treated the same as an\nunmodified index entry.  The index will be updated, and when you check\nout the revision, the working directory file will be (re-)created.\n\nNote that none of this affects you in the usual case where you make\nchanges in the working directory only, and leave the index equal to HEAD\nuntil you're ready to commit.\n\n\n* Packs\n\nOriginally, git stored every object in its own file, and used rsync\nto share repositories.  It was quickly discovered that this brought\nmighty servers to their knees.  It's great for retrieving a small\nsubset of the database the way git usually does, but rsync scans the\nwhole .git/objects tree every time.\n\nSo packs were developed.  A pack is a file, built all at once, which\ncontains many delta-compressed objects.  With each .pack file,\nthere's an accompanying .idx file that indexes the pack so that\nindividual objects can be retrieved quickly.\n\nYou can reduce the disk space used by your repositories by periodically\nrepacking them with git-repack.  Normally, this makes a new incremental\npack of everything not already packed.  With the -a flag, this repacks\neverything for even greater compression (but takes longer).\n\nThe git wire protocol basically consists of negotiation over what\nobjects needs to be transferred followed by sending a custom-built pack.\nThe .idx file can be reconstructed from the .pack file, so it's\nnever transferred.\n\n[[ Is once every few hundred commits a good rule of thumb for repacking?\nWhen .git/objects/?? reaches X megabytes?  I think too many packs is\nitself a bad thing, since they all have to be searched. ]]\n\n\n* Raw diffs\n\nA major source of git's speed is that it tries to avoid accessing files\nunnecessarily.  In particular, files can be compared based on their\nobject IDs without needing to open and read them.  As part of this,\nthe responsibility for finding file differences (printing diffs) is\ndivided into finding what files have changed, and finding the changes\nwithin those files.\n\nThis is all explained in the Documentation/diffcore.txt in the git\ndistribution, but the basics is that many of the primitives spit out a\nline like this:\n:100755 100755 68838f3fad1d22ab4f14977434e9ce73365fb304 0000000000000000000000000000000000000000 M\tgit-bisect.sh\nwhen asked for a diff.  This is known as a \"raw diff\".  They can be\ntold to generate a human-readable diff with the \"-p\" (patch) flag.\nThe git-diff command includes this by default.\n\n\n* Advice on using git\n\nIf you're used to CVS, where branches and merges are \"advanced\" features\nthat you can go a long time, you need to learn to use branches in git a\nlot more.  Branch early and often.  Every time you think about developing\na feature or fixing a bug, create a branch to do it on.\n\nIn fact, avoid doing any development on the master branch.  Merges only.\n\nA branch is the git equivalent of a patch, and merging a branch is the\nequivalent of applying that patch.  A branch gives it a name that\nyou can use to refer to it.  This is particularly useful if you're\nsharing your changes.\n\nOnce you're done with a branch, you can delete it.  This is basically\njust removing the refs/heads/<branch> file, but \"git-branch -d\" adds a\nfew extra safety checks.  Assuming you merged the branch in, you can\nstill find all the commits in the history, it's just the name that's\nbeen deleted.\n\nYou can also rename a branch by renaming the refs/heads/branch file.\nThere's no git command to do this, but as long as you update\nthe HEAD symlink if necessary, you don't need one.\n\nPeriodically merge all of the branches you're working on into a testing\nbranch to see if everything works.  Blow away and re-create the\ntesting branch whenever you do this.  When you like the result,\nmerge them into the master.\n\n\n* The .git directory\n\nThere are a number of files in the .git directory used by the\nporcelain.  In case you're curious (I was), this is what they are:\n\nindex\n- The actual index file.\n\nobjects/\n- The object database.  Can be overridden by $GIT_OBJECT_DIRECTORY\n\nhooks/\n- where the hook scripts are kept.  The standard git template includes\n  examples, but disabled by being marked non-executable.\n\ninfo/exclude\n- Default project-wide list of file patterns to exclude from notice.\n  To this is added the per-directory list in .gitignore.\n  See the git-ls-files docs for full details.\n\nrefs/\n- References to development heads (branches) and tags.\n\nremotes/\n- Short names of remote repositories we pull from or push to.\n  Details are in the \"git-fetch\" man page.\n\nHEAD\n- The current default development head.\n- Created by git-init-db and never deleted\n- Changed by git-checkout\n- Used by git-commit and any other command that commits changes.\n- May be a dangling pointer, in which case git-commit\n  does an \"initial checkin\" with no parent.\n\nCOMMIT_EDITMSG\n- Temp used by git-commit to edit a commit message.\nCOMMIT_MSG\n- Temp used by git-commit to form a commit message,\n  post-processed from COMMIT_EDITMSG.\n\nFETCH_HEAD\n- Just-fetched commits, to be merged into the local trunk.\n- Created by git-fetch.\n- Used by git-pull as the source of data to merge.\n\nMERGE_HEAD\n- Keeps track of what heads are currently being merged into HEAD.\n- Created by git-merge --no-commit with the heads used \n- Deleted by git-checkout and git-reset (since you're abandoning\n  the merge)\n- Used by git-commit to supply additional parents to the current commit.\n  (And deleted when done.)\n\nMERGE_MSG\n- Generated by git-merge --no-commit.\n- Used by git-commit as the commit message for a merge\n  (If present, git-commit doesn't prompt.)\n\nMERGE_SAVE\n- cpio archive of all locally modified files created by\n  \"git-merge\" before starting to do anything, if multiple\n  merge strategies are being attempted.\n  Used to rewind the tree in case a merge fails.\n\nORIG_HEAD\n- Previous HEAD commit prior to a merge or reset operation.\n\nLAST_MERGE\n- Set by the \"resolve\" strategy to the most recently merged-in branch.\n  Basically, a copy of MERGE_HEAD.  Not used by the other merge strategies,\n  and resolve is no longer the default, so its utility is very limited.\n\nBISECT_LOG\n- History of a git-bisect operation.\n- Can be replayed (or, more usefully, a prefix can) by \"git-bisect replay\"\nBISECT_NAMES\n- The list of files to be modified by git-bisect.\n- Set by \"git-bisect start\"\n\nTMP_HEAD (used by git-fetch)\nTMP_ALT (used by git-fetch)\n\n\n* Git command summary\n\nThere are slightly over a hundred git commands.  This section tries to\nclassify them by purpose, so you can know which commands are intended to\nbe used for what.  You can always use the low-level plumbing directly,\nbut that's inconvenient and error-prone.\n\nHelper programs (not for direct use) for a specific utility are shown\nindented under the program they help.\n\nNote that all of these can be invoked using the \"git\" wrapper by replacing\nthe leading \"git-\" with \"git \".  The results are exactly the same.\nThere is a suggestion to reduce the clutter in /usr/bin and move all\nthe git binaries to their own directory, leaving just the git wrapper\nin /usr/bin. so you'll have to use it or adjust your $PATH.  But that\nhasn't happened yet.  In the meantime, including the hyphen makes\ntab-completion work.\n\nI include \".sh\", \".perl\", etc. suffixes to show what the programs are\nwritten in, so you can read those scripts written in languages you're\nfamiliar with.  These are the names in the git source tree, but the\nsuffix is not included in the /usr/bin copies.\n\n+ Administrative commands\ngit-init-db\n\n+ Object database maintenance:\ngit-convert-objects\ngit-fsck-objects\ngit-lost-found.sh\ngit-prune.sh\ngit-relink.perl\n\n+ Pack maintenance\ngit-count-objects.sh\ngit-index-pack\ngit-pack-objects\ngit-pack-redundant\ngit-prune-packed\ngit-repack.sh\ngit-show-index\ngit-unpack-objects\ngit-verify-pack\n\n+ Important primitives\ngit-commit-tree\ngit-rev-list\ngit-rev-parse\n\n+ Useful primitives\ngit-ls-files\ngit-update-index\n\n+ General script helpers (used only by scripts)\ngit-cat-file\ngit-check-ref-format\ngit-checkout-index\ngit-fmt-merge-msg.perl\ngit-hash-object\ngit-ls-tree\ngit-repo-config\ngit-unpack-file\ngit-update-ref\ngit-sh-setup.sh\ngit-stripspace\ngit-symbolic-ref\ngit-var\ngit-write-tree\n\n+ Oddballs\ngit-mv.perl\n\n+ Code browsing\ngit-diff.sh\n  git-diff-files\n  git-diff-index\n  git-diff-tree\n  git-diff-stages\ngit-grep.sh\ngit-log.sh\ngit-name-rev\ngit-shortlog.perl\ngit-show-branch\ngit-whatchanged.sh\n\n+ Making local changes\ngit-add.sh\ngit-bisect.sh\ngit-branch.sh\ngit-checkout.sh\ngit-commit.sh\ngit-reset.sh\ngit-status.sh\n\n+ Cherry-picking\ngit-cherry.sh\n  git-patch-id\ngit-cherry-pick.sh\ngit-rebase.sh\ngit-revert.sh\n\n+ Accepting changes by e-mail\ngit-apply\ngit-am.sh\n  git-mailinfo\n  git-mailsplit\n  git-applypatch.sh\ngit-applymbox.sh\n\n+ Publishing changes by e-mail\ngit-format-patch.sh\ngit-send-email.perl\n\n+ Merging\ngit-merge.sh\n  git-merge-base\n  git-merge-index\n    git-merge-one-file.sh\n  git-merge-octopus.sh\n  git-merge-ours.sh\n  git-merge-recursive.py\n  git-merge-resolve.sh\n  git-merge-stupid.sh\ngit-read-tree\ngit-resolve.sh\ngit-octopus.sh\n\n+ Making releases\ngit-get-tar-commit-id\ngit-tag.sh\n  git-mktag\ngit-tar-tree\ngit-verify-tag.sh\n\n+ Accepting changes by network\ngit-clone.sh\n  git-clone-pack\ngit-fetch.sh\n  git-fetch-pack\n  git-local-fetch\n  git-http-fetch\n  git-ssh-fetch\ngit-ls-remote.sh\n  git-peek-remote\ngit-parse-remote.sh\ngit-pull.sh\n  git-ssh-pull\ngit-shell\n  git-receive-pack\n\n+ Publishing changes by network\ngit-daemon\n\ngit-push.sh\n  git-http-push\n  git-ssh-push\n  git-ssh-upload\ngit-request-pull.sh\ngit-send-pack\ngit-update-server-info\ngit-upload-pack\n\nAll of the basic git commands are designed to be scripted.  When\nscripting, use the \"--\" option to ensure that files beginning with\n\"-\" won't be interpreted as options, and the \"-z\" option to output\nNUL-terminated file names so embedded newlines won't break things.\n\n(A person who'd do either of these on purpose is probably crazy, but\nit's not actually illegal.)\n\nLooking at existing shell scripts can be very informative.\n\n\n\n* Detailed list\n\nHere's a repeat, including descriptions.  I don't try to include\nevery detail you can find on the man page, but to explain when\nyou'd want to use a command.\n\n+ Administrative commands\ngit-init-db\n\tThis creates an empty git repository in ./.git (or $GIT_DIR if\n\tthat is non-null) using a system-wide template.\n\tIt won't hurt an existing repository.\n\n+ Object database maintenance:\ngit-convert-objects\n\tYou will *never* need to use this command.\n\tThe git repository format has undergone some revision since its\n\tfirst release.  If you have an ancient and crufty git repository\n\tfrom the very very early days, this will convert it for you.\n\tBut as you're new to git, it doesn't apply.\ngit-fsck-objects\n\tValidate the object database.  Checks that all references\n\tpoint somewhere, all the SHA1 hashes are correct, and that\n\tsort of thing.\n\n\tThis walks the entire repository, uncompressing and hashing\n\tevery object, so it takes a while.  Note that by default,\n\tit skips over packs, which can make it seem misleadingly fast.\ngit-lost-found.sh\n\tFind (using git-fsck-objects) any unreferenced commits and\n\ttags in the object database, and place them in a .git/lost-found\n\tdirectory.  This can be used to recover from accidentally\n\tdeleting a tag or branch reference that you wanted to keep.\n\n\tThis is the opposite of git-prune.\ngit-prune.sh\n\tDelete all unreachable objects from the object database.\n\tIt deletes useless packs, but does not remove useless\n\tobjects from the middle of partially useful packs.\n\n\tGit leaks objects in a number of cases, such as unsuccessful\n\tmerges.  The leak rate is generally a small fraction of\n\tthe rate at which the desired history grows, so it's not\n\tvery alarming, but occasionally running git-prune will\n\teliminate the \n\n\tIf you deliberately throw away a development branch, you\n\twill need to run this command to fully reclaim the disk space.\n\n\tOn something like the full Linux repository, this takes\n\ta while.\ngit-relink.perl\n\tMerge the objects stores of multiple git repositories by\n\tmaking hard links between them.  Useful to save space if\n\tduplicate copies are accidentally created on one machine.\n\n+ Pack maintenance\n\tThe classic git format is to compress and store each object\n\tseparately.  This is still used for all newly created changes.\n\tHowever, objects can also be stored en masse in \"packs\" which\n\tcontain many objects and tan take advantage of delta-compressing.\n\tRepacking your repositories periodically can save space.\n\t(Repacking is pretty quick but not quick enough to be\n\tcomfortable doing every commit.)\ngit-count-objects.sh\n\tPrint the number and total size of unpacked objects in the\n\trepository, to help you decide when is a good time to repack.\ngit-index-pack\n\tA pack file has an accompanying .idx file to allow rapid lookup.\n\tThis regenerates the .idx file from the .pack.  This is almost never\n\tneeded directly, but can be used after transferring a .pack file\n\tbetween machines.\ngit-pack-objects\n\tGiven a list of objects on stdin, build a pack file.  This is\n\ta helper used by the various network communication scripts.\ngit-pack-redundant\n\tProduce a list of redundant packs, for feeding to \"xargs rm\".\n\tA helper for git-prune.\ngit-prune-packed\n\tDelete unpacked object files that are duplicated in packs.\n\t(With -n, only lists them.)  A helper for git-prune.\ngit-repack.sh\n\tMake a new pack with all the unpacked objects.\n\tWith -a, include already-packed objects in the new pack.\n\tWith -d as well, deletes all the old packs thereby made redundant.\ngit-show-index\n\tDump the contents of a pack's .idx file.  Mostly for\n\tdebugging git itself.\ngit-unpack-objects\n\tUnpack a .pack file, the opposite of git-pack-objects.\tWith -n,\n\tdoesn't actually create the files.  With -q, suppresses the\n\tprogress indicator.\ngit-verify-pack\n\tValidate a pack file.  Useful when debugging git, and when\n\tdownloading from a remote source.  A helper for git-clone.\n\n+ Important primitives\n\tAlthough these primitives are not used directly very frequently,\n\tunderstanding them will help you understand other git commands\n\tthat wrap them.\ngit-commit-tree\n\tCreate a new commit object from a tree and a list of parent\n\tcommits.  This is the primitive that's the heart of git-commit.\n\t(It's also used by git-am, git-applypatch, git-merge, etc.)\ngit-rev-list\n\tPrint a list of commits (revisions), in reverse chronological\n\torder.  This is the heart of git-log and other history examination\n\tcommands, and the options for specifying parts of history are\n\tshared by all of them.\n\n\tIn particular, it takes an arbitrary number of revisions as\n\targuments, some of which may be prefixed with ^ to negate them.\n\tThese make up \"include\" and \"exclude\" sets.  git-rev-list\n\tlists all revisions that are ancestors of the \"include\" set\n\tbut not ancestors of the \"exclude\" set.\n\t\n\tFor this purpose, a revision is considered an ancestor of itself.\n\tThus, \"git-rev-list ^v1.1 v1.2\" will list all revisions from\n\tthe v1.2 release back to (but not including) the v1.1 release.\n\n\tBecause this is so convenient, a special syntax, \"v1.1..v1.2\"\n\tis allowed as an equivalent.  However, occasionally the general\n\tform is useful.  For example, adding ^branch will show the trunk\n\t(including merges from the branch), but exclude the branch itself.\n\n\tSimilarly, \"branch ^trunk\", a.k.a. trunk..branch, will show\n\tall work on the branch that hasn't been merged to the trunk.\n\tThis works even though trunk is not a direct ancestor of branch.\n\t\n\tGit-rev-list has a variety of flags to control it output format.\n\tThe default is to just print the raw SHA1 object IDs of the\n\tcommits, but --pretty produces a human-readable log.\n\n\tYou can also specify a set of files names (or directories),\n\tin which case output will be limited to commits that modified\n\tthose files.\n\n\tThis command is used extensively by the git:// protocol to compute\n\ta set of objects to send to update a repository.\ngit-rev-parse\n\tThis is a very widely used command line canonicalizer for git\n\tscripts.  It converts relative commit references (e.g. master~3)\n\tto absolute SHA1 hashes, and can also pass through arguments\n\tnot recognizable as references, so the script can interpret them.\n\n\tIt is important because it defines the <rev> syntax.\n\n\tThis takes a variety of options to specify how to prepare the\n\tcommand line for the script's use.  --verify is a particularly\n\timportant one.\n\n+ Useful primitives\n\tThese primitives are potentially useful directly.\ngit-ls-files\n\tList files in the index and/or working directory.  A variety of\n\toptions control which files to list, based on whether they\n\tare the same in both places or have been modified.  This command\n\tis the start of most check-in scripts.\ngit-update-index\n\tCopy the given files from the working directory into the index.\n\tThis create the blob objects, but no trees yet.  (Note that\n\tediting a file executing this multiple times without creating a\n\tcommit will generate orphaned objects.  Harmless.)\n\n\tOne common safe option is \"git-update-index --refresh\".  This\n\tlooks for files whose metadata (modification time etc.) has\n\tchanged, but not their contents, and updates the metadata in the\n\tindex so the file contents won't have to be examined again.\n\n+ General script helpers (used only by scripts)\n\tThese are almost exclusively helpers for use in porcelain\n\tscripts and have little use by themselves from the command line.\ngit-cat-file\n\tExtract a file from the object database.  You can ask for\n\tan object's type or size given only an object ID, but\n\tto get its contents, you have to specify the type.  This\n\tis a deliberate safety measure.\ngit-check-ref-format\n\tVerify that the reference specified on the command line is\n\tsyntactically valid for a new reference name under $GIT_DIR/refs.\n\tA number of characters (^, ~, :, and ..) are reserved; see the man\n\tpage for the full list of rules.\ngit-checkout-index\n\tCopy files from the index to the working directory, or to a\n\tspecified directory.  Most important as a helper for git-checkout,\n\tthis is also used by git-merge and git-reset.\ngit-fmt-merge-msg.perl\n\tGenerate a reasonable default commit message for a merge.\n\tUsed by git-pull and git-octopus.\ngit-hash-object\n\tVery primitive helper to turn an arbitrary file into an object,\n\treturning just the ID or actually adding it to the database.\n\tUsed by the cvs-to-git and svn-to-git import filters.\ngit-ls-tree\n\tList the contents of a tree object.  Will tell you all the files\n\tin a commit.  Used by the checkout scripts git-checkout and git-reset.\ngit-repo-config\n\tGet and set options in .git/config.  The .git/config format\n\tis designed to be human-readable.  This gives programmatic\n\taccess to the settings.  This currently has a lot of overlap\n\twith the function of git-var.\ngit-unpack-file\n\tWrite the contents of the given block to a temporary file,\n\tand return the name of that temp file.  Used most often\n\tby merging scripts.\ngit-update-ref\n\tRewrite a reference (in .git/refs/) to point to a new object.\n\t\"echo $sha1 > $file\" is mostly equivalent, but this adds locking\n\tso two people don't update the same reference at once.\ngit-sh-setup.sh\n\tThis is a general prefix script that sets up\n\t$GIT_DIR and $GIT_OBJECT_DIRECTORY for a script,\n\tor errors out if the git control files can't be found.\ngit-stripspace\n\tRemove unnecessary whitespace.  Used mostly on commit messages\n\treceived by e-mail.\ngit-symbolic-ref\n\tThis queries or creates symlinks to references such as HEAD.\n\tBasically equivalent to readlink(1) or ln -s, this also works\n\ton platforms that don't have symlinks.  See the man page.\ngit-var\n\tProvide access to the GIT_AUTHOR_IDENT and/or GIT_COMMITTER_IDENT\n\tvalues, used in various commit scripts.  This currently has a\n\tlot of overlap with the function of git-repo-config.\ngit-write-tree\n\tGenerate a tree object reflecting the current index.  The output\n\tis the tree object; if you don't remember it somewhere (usually,\n\tpass it to git-commit-tree), it'll be lost.\n\n\tThis requires that the index be fully merged.  If any incomplete\n\tmerges are present in the index (files in stages 1, 2 or 3),\n\tgit-write-tree will fail.\n\n+ Oddballs\ngit-mv.perl\n\tI have to admit, I'm not quite sure what advantages this is\n\tsupposed to have over plain \"mv\" followed by \"git-update-index\",\n\tor why it's complex enough to need perl.\n\n\tBasically, this renames a file, deleting its old name and adding\n\tits new name to the index.  Otherwise, it's a two-step process\n\tto rename a file:\n\t- Rename the file\n\t- git-add the new name\n\tFollowed by which you must commit both the old and new names\n\n+ Code browsing\ngit-diff.sh\n\tShow changes between various trees.  Takes up to two tree\n\tspecifications, and shows the difference between the versions.\n\tZero arguments: index vs. working directory (git-diff-files)\n\tOne: tree vs. working directory (git-diff-index)\n\tOne, --cached: tree vs. index (git-diff-index)\n\tTwo: tree vs. tree (git-diff-tree)\n\n\tThis wrapper always produces human-readable patch output.\n\tThe helpers all produce \"diff-raw\" format unless you supply\n\tthe -p option.\n\n\tThere are some interesting options.  Unfortunately, the git-diff\n\tman page is annoyingly sparse, and refers to the helper scripts'\n\tdocumentation rather than describing the many useful options\n\tthey all have in common.  Please do read the man pages of the\n\thelpers to see what's available.\n\t\n\tIn particular, although git does not explicitly record file\n\trenames, it has some pretty good heuristics to notice things.\n\t-M tries to detect renamed files by matching up deleted files\n\twith similar newly created files.  -C tries to detect copies\n\tas well.  By default, -C only looks among the modified files for\n\tthe copy source.  For common cases like splitting a file in two,\n\tthis works well.  The --find-copies-harder searches ALL files\n\tin the tree for the copy source.  This can be slow on large trees!\n\n\tSee Documentation/diffcore.txt for an explanation of how all\n\tthis works.\n  git-diff-files\n\tCompare the index and the working directory.\n  git-diff-index\n\tCompare the working directory and a given tree.  This is the\n\tgit equivalent of the single-operand form of \"cvs diff\".\n\tIf \"--cached\" is specified, uses the index rather than the working\n\tdirectory.\n  git-diff-tree\n\tCompare two trees.  This is the git equivalent of the two-operand\n\tform of \"cvs diff\".  This command is sometimes useful by itself\n\tto see the changes made by a single commit.  If you give it\n\tonly one commit on the command line, it shows the diff between\n\tthat commit and its first parent.  If the commit specification\n\tis long and awkward to type, using \"git-diff-tree -p <commit>\"\n\tcan be easier than \"git-diff <commit>^ <commit>\".\n  git-diff-stages\n\tAlthough not called by git-diff, there is a fourth diff helper\n\troutine, used to compare the various versions of an unmerged\n\tfile in the index.  It is intended for use by merging porcelain.\ngit-grep.sh\n\tA very simple wrapper that runs git-ls-files and greps the\n\toutput looking for a file name.  Does nothing fancy except\n\tsaves typing.\ngit-log.sh\n\tWrapper around git-rev-list --pretty.  Shows a history\n\tof changes made to the repository.  Takes all of git-rev-list's\n\toptions for specifying which revisions to list.\ngit-name-rev\n\tFind a symbolic name for the commit specified on the\n\tcommand line, and returns a symbolic name of the form\n\t\"maint~404^2~7\".  Basically, this does a breadth-first search\n\tfrom all the heads in .git/refs looking for the given commit.\ngit-shortlog.perl\n\tThis is a filter for the output of \"git-log --pretty=short\"\n\tto generate a one-line-per-change \"shortlog\" as Linus likes.\ngit-show-branch\n\tVisually show the merge history of the references given as\n\targuments.  Prints one column per reference and one line per\n\tcommit showing whether that commit is an ancestor of each\n\treference.\ngit-whatchanged.sh\n\tA simple wrapper around git-rev-list and git-diff-tree,\n\tthis shows the change history of a repository.  Specify a\n\tdirectory or file on the command line to limit the\n\toutput to changes affecting those files.  This isn't\n\tthe same as \"cvs annotate\", but it serves a similar purpose\n\tamong git folks.\n\n\tYou can add the -p option to include patches as well as log\n\tcomments.  You can also add the -M or -C option to follow\n\thistory back through file renames.\n\n\t-S is interesting: it's the \"pickaxe\" option.  Given a string,\n\tthis limits the output to changes that make that string appear\n\tor disappear.  This is for \"digging through history\" to see when\n\ta piece of code was introduced.  The string may (and often does)\n\tcontain embedded newlines.  See Documentation/cvs-migration.txt.\n\n+ Making local changes\n\tAll of these are examples of \"porcelain\" scripts.  Reading the\n\tscripts themselves can be informative; they're generally not\n\ttoo confusing.\ngit-add.sh\n\tA simple wrapper around \"git-ls-files | git-update-index --add\"\n\tto add new files to the index.   You may specify directories.\n\tYou need to invoke this for every new file you want git to\n\ttrack.\ngit-bisect.sh\n\tUtility to do a binary search to find the change that broke something.\n\tThe heart of this is in \"git-rev-list --bisect\"\n\tA very handy little utility!  Kernel developers love it\n\twhen you tell them exactly which patch broke something.\n\tNOTE: this uses the head named \"bisect\", and will blow\n\taway any existing branch by that name.  Try not to\n\tcreate a branch with that name.\n\n\tThere are three steps:\n\tgit-bisect start [<files>]\n\t\t- Reset to start bisecting.  If any files are specified,\n\t\t  only they will be checked out as bisection proceeds.\n\tgit-bisect good [<revision>]\n\t\t- Record the revision as \"good\".  The change being sought\n\t\t  must be after this revision.\n\tgit-bisect bad [<revision>]\n\t\t- Record the revision as \"bad\".  The change being sought\n\t\t  must be before or equal to this revision.\n\tAs soon as you have specified one good version and one bad version,\n\tgit-bisect will find a halfway point and check out that\n\trevision.  Build and test it, then report it as good or bad,\n\tand git-bisect will narrow the search.  Finally, git-bisect\n\twill tell you exactly which change caused the problem.\n\tgit-bisect log\n\t\t- Show a history of revisions.\n\tgit-bisect replay\n\t\t- Replay (part of) a git-bisect log.  Generally used\n\t\t  to recover from a mistake, you can truncate the log\n\t\t  before the mistake and replay it to continue.\n\tIf git-bisect chooses a version that cannot build, or you\n\tare otherwise unable to determine whether it is good or bad,\n\tyou can change revisions with \"git-reset --hard <revision>\"\n\tto another checkout between the current good and bad limits, and\n\tcontinue from there.  \"git-reset --hard <revision>\" is generally\n\tdangerous, but you are on a scratch branch.\n\n\tThis can, of course, be used to look for any change, even\n\tone for the better, if you can avoid being confused by the\n\tterms \"good\" and \"bad\".\ngit-branch.sh\n\tMost commonly used bare, to show the available branches.\n\tShow, create, or delete a branch.  The current branches\n\tare simply the contents of .git/refs/heads/.\n\tNote that this does NOT switch to the created branch!\n\tFor the common case of creating a branch and immediately\n\tswitching to it, \"git-checkout -b <branch>\" is simpler.\ngit-checkout.sh\n\tThis does two superficially similar but very different things\n\tdepending on whether any files or paths are specified on the\n\tcommand line.\n\n\tgit-checkout [-f] [-b <new-branch>] <branch>\n\t\tThis switches (changes the HEAD symlink to) the specified\n\t\tbranch, updating the index and working directory to\n\t\treflect the change.  This preserves changes in the\n\t\tworking directory unless -f is specified.\n\t\tIf -b is specified, a new branch is started from the\n\t\tspecified point and switched to.  If <branch> is omitted,\n\t\tit defaults to HEAD.  This is the usual way to start a\n\t\tnew branch.\n\n\tgit-checkout [<branch>] [--] <paths>...\n\t\tThis replaces the files specified by the given paths with\n\t\tthe versions from the index or the specified branch.\n\t\tIt does NOT affect the HEAD symlink, just replaces the\n\t\tspecified paths.  This form is like a selective form of\n\t\t\"git-reset\".  Normally, this can guess whether the first\n\t\targument is a branch name or a path, but you can use\n\t\t\"--\" to force the latter interpretation.\n\n\tWith no branch, this is used to revert a botched edit of a\n\tparticular file.\n\n\tBoth forms use git-read-tree internally, but the net effect is\n\tquite different.\ngit-commit.sh\n\tCommit changes to the revision history.  In terms of primitives,\n\tthis does three things:\n\t1) Updates the index file with the working directory files\n\t   specified on the command line, or -a for all\n\t   (using git-diff-files --name-only | git-update_index),\n\t2) Prompts for or generates a commit message, and then\n\t3) Creates a commit object with the current index contents.\n\n\tThis also executes the pre-commit, commit-msg, and\n\tpost-commit hooks if present.\n\n\tThis will remove deleted files from the index, but will not\n\tadd new files to the index, even if explicitly specified on the\n\tcommand line; you must use git-add for that.\ngit-reset.sh\n\tExplained in detail in \"resetting\", above.  This modifies the\n\tcurrent branch head reference (as pointed to by .git/HEAD)\n\tto refer to the given commit.  It does not modify .git/HEAD \n\tReset the current HEAD to the specified commit, so that future\n\tcheckins will be relative to it.  There are three\n\tvariations:\n\t--soft: Just move the HEAD link.  The index is unchanged.\n\t--mixed (default): Move the HEAD link and update the index file.\n\t\tAny local changes will appear not checked in.\n\t--hard: Move the HEAD links, update the index file, and\n\t\tcheck out the index, overwriting the working\n\t\tdirectory.  Like \"cvs update -C\".\n\tIn case of accidents, this copies the previous head\n\tobject ID to ORIG_HEAD (which is NOT a symlink).\ngit-status.sh\n\tShow all files in the directory not current with respect\n\tto the git HEAD.  The basic categories are:\n\t1) Changed in the index, will be included in the next commit.\n\t2) Changed in the working directory but NOT in the index; will\n\t   be committed only if added via git-update-index or the\n\t   git-commit command line.\n\t3) Not tracked by git.\n\n+ Cherry-picking\n\tCherry-picking is the process of taking part of the changes\n\tintroduced on one tree and applying those changes to another.\n\tThis doesn't produce a parent/descendant relationship in the\n\tcommit history.\n\n\tTo produce that relationship, there's a special type of merge you\n\tcan do if you've taken everything you want off a branch and\n\twant to show it in the merge history without actually importing\n\tany changes from it: ours.  \"git-merge -s ours\" will generate a\n\tcommit that shows some branches were merged in, but not\n\tactually alter the current HEAD source code in any way.\n\n\tOne thing cherry-picking is sometimes used for is taking a\n\tdevelopment branch and re-organizing the changes into a patch\n\tseries for submission to the Linux kernel.\ngit-cherry.sh\n\tThis searches a branch for patches which have not been applied\n\tto another.  Basically, it finds the unpicked cherries.\n\tIt searches back to the common ancestor of the named branch and\n\tthe current head using git-patch-id to identify similarity\n\tin patches.\n  git-patch-id\n\tGenerate a hash of a patch, ignoring whitespace and line numbers\n\tso that \"the same\" patch, even relative to a different code base,\n\tprobably has the same hash, and different patches probably have\n\tdifferent ones.  git-cherry looks for patch hashes which \n\tare present on the branch (source branch) that are not present\n\ton the trunk (destination branch).\ngit-cherry-pick.sh\n\tGiven a commit (on a different branch), compute a diff between\n\tit and its immediate parent, and apply it to the current HEAD.  \n\tThis is actually the same script as \"git revert\", but\n\tworks forward.  git-cherry finds the patches, this merges them.\n\tHandles failures gracefully.\ngit-rebase.sh\n\tMove a branch to a more recent \"base\" release.\tThis just extracts\n\tall the patches applied on the local head since the last merge\n\twith upstream (using git-format-patch) and re-applies them\n\trelative to the current upstream with git-am (explained under\n\t\"accepting changes by e-mail\").  Finally, it deletes the old\n\tbranch and gives its name to the new one, so your branch now\n\tcontains all the same changes, but relative to a different base.\n\tBasically the same as cherry-picking an entire branch.\ngit-revert.sh\n\tUndo a commit.\tBasically \"patch -R\" followed by a commit.\n\tThis is actually the same script as \"git-cherry-pick\", just\n\tapplies the patch in reverse, undoing a change that you don't\n\twish to back up to using git-reset.  Handles failures gracefully\n\tby telling the user what to do.\n\n+ Accepting changes by e-mail\ngit-apply\n\tApply a (git-style extended) patch to the current index\n\tand working directory.\ngit-am.sh\n\tThe new and improved \"apply an mbox\" script.  Takes an\n\tmbox-style concatenation of e-mails as input and batch-applies\n\tthem, generating one commit per message.  Can resume after\n\tstopping on a patch problem.\n\t(Invoke it as \"git-am --skip\" or \"git-am --resolved\" to\n\tdeal with the problematic patch and continue.)\n  git-mailinfo\n\tGiven a single mail message on stdin (in the Linux standard\n\tSubmittingPatches format), extract a commit message and\n\tthe patch proper.\n  git-mailsplit\n\tSplit an mbox into separate files.\n  git-applypatch.sh\n\tTries simple git-apply, then tries a few other clever merge\n\tstrategies to get a patch to apply.  Used in the main loop\n\tof git-am and git-applymbox.\ngit-applymbox.sh\n\tThis is Linus's original apply-mbox script.  Mostly superseded by\n\tgit-am (which is friendlier and has more features), but he still\n\tuses it, so it's maintained.  This is so old it was originally\n\ta test of the git core called \"dotest\", and that name is still\n\tlurking in the temp file names.\n\n+ Publishing changes by e-mail\ngit-format-patch.sh\n\tGenerate a series of patches, in the preferred Linux kernel\n\t(Documentation/SubmittingPatches) format, for posting to lkml\n\tor the like.  This formats every commit on a branch as a separate\n\tpatch.\ngit-send-email.perl\n\tActually e-mail the output of git-format-patch.\n\t(This uses direct SMTP, a matter of some controversy.  Others feel\n\tthat /bin/mail is the correct local mail-sending interface.)\n\n+ Merging\ngit-merge.sh\n\tMerge one or more \"remote\" heads into the current head.\n\tSome changes, when there has been change only on one branch or\n\tthe same change has been made to all branches, can be resolved\n\tby the \"trivial in-index\" merge done by git-read-tree.\tFor more\n\tcomplex cases, git provides a number of different merge strategies\n\t(with reasonable defaults).\n\n\tNote that merges are done on a filename basis.\tWhile git tries\n\tto detect renames when generating diffs, most merge strategies\n\tdon't track them by renaming.  (The \"recursive\" strategy, which\n\trecently became the default, is a notable exception.)\n  git-merge-base\n\tFinds a common ancestor to use when comparing the changes made\n\ton two branches.  The simple case is straightforward, but if\n\tthere have been cross-merges between the branches, it gets\n\tsomewhat hairy.  The algorithm is not 100% final yet.\n\t(There's also --all, which lists all candidates.)\n  git-merge-index\n\tThis is the outer merging loop.  It takes the name of a one-file\n\tmerge executable as an argument, and runs it for every incomplete\n\tmerge.\n    git-merge-one-file.sh\n\tThis is the standard git-merge-index helper, that tries to\n\tresolve a 3-way merge.  A helper used by all the merge strategies.\n\t(Except \"recursive\" which has its own equivalent.)\n  git-merge-octopus.sh\n\tMany-way merge.  Overlaps should be negligible.\n  git-merge-ours.sh\n\tA \"dummy\" merge strategy helper.  Claims that we did the merge, but\n\tactually takes the current tree unmodified.  This is used to\n\tcleanly terminate side branches that heve been cherry-picked in.\n  git-merge-recursive.py\n\tA somewhat fancier 3-way merge.   This handles multiple cross-merges\n\tbetter by using multiple common ancestors.\n  git-merge-resolve.sh\n  git-merge-stupid.sh\n\tNot actually used by git-merge, this is a simple example\n\tmerge strategy.\ngit-read-tree\n\tRead the given tree into the index.  This is the difference\n\tbetween the \"--soft\" and \"--mixed\" modes of git-reset, but the\n\timportant thing this command does is simple merging.\n\tIf -m is specified, this can take up to three trees as arguments.\ngit-resolve.sh\n\tOBSOLETE.  Perform a merge using the \"resolve\" strategy.\n\tHas been superseded by the \"-s resolve\" option to git-merge\n\tand git-pull.\ngit-octopus.sh\n\tOBSOLETE.   Perform a merge using the \"octopus\" strategy.\n\tHas been superseded by the \"-s octopus\" option to git-merge\n\tand git-pull.\n\n+ Making releases\ngit-get-tar-commit-id\n\tReads out the commit ID that git-tar-tree puts in its output.\n\t(Or fails if this isn't a git-generated tar file.)\ngit-tag.sh\n\tCreate a tag in the refs/tags directory.  There are two kinds:\n\t\"lightweight tags\" are just references to commits.  More\n\tserious tags are GPG-signed tag objects, and people receiving\n\tthe git tree can verify that it is the version that you released.\n  git-mktag\n\tCreates a tag object.  Verifies syntactic correctness of its\n\tinput.  (If you want to cheat, use git-hash-object.)\ngit-tar-tree\n\tGenerate a tar archive of the named tree.  Because git does NOT\n\ttrack file timestamps, this uses the timestamp of the commit,\n\tor the current time if you specify a tree.\n\tAlso stores the commit ID in an extended tar header.\ngit-verify-tag.sh\n\tGiven a tag object, GPG-verify the embedded signature.\n\n+ Accepting changes by network\n\tPulling consists of two steps: retrieving the remote commit\n\tobjects and everything they point to (including ancestors),\n\tthen merging that into the desired tree.  There are still\n\tseparate fetch and merge commands, but it's more commonly done\n\twith a single \"git-pull\" command.  git-fetch leaves the commit\n\tobjects, one per line, in .git/FETCH_HEAD.  git-merge will\n\tmerge those in if that file exists when it is run.\n\n\tReferences to remote repositories can be made with long URLs,\n\tor with files in the .git/remotes/ directory.  The latter\n\talso specifies the local branches to merge the fetched data into,\n\tmaking it very easy to track a remote repository.\ngit-clone.sh\n\tCreate a new local clone of a remote repository.\n\t(Can do a couple of space-sharing hacks when \"remote\" is on\n\ta local machine.)\n\n\tYou only do this once.\n  git-clone-pack\n\tRuns git-upload-pack remotely and places the resultant pack\n\tinto the local repository.  Supports a variety of network\n\tprotocols, but \"remote\" can also be a different directory on\n\tthe current machine.\ngit-fetch.sh\n\tFetch the named refs and all linked objects from a remote repository.\n\tThe resultant refs (tags and commits) are stored in .git/FETCH_HEAD,\n\twhich is used by a later git-resolve or git octopus.\n\n\tThis is the first half of a \"git pull\" operation.\n  git-fetch-pack\n\tRetrieve missing objects from a remote repository.\n  git-local-fetch\n\tDuplicates a git repository from the local system.\n\t(Er... is this used anywhere???)\n  git-http-fetch\n\tDo a fetch via http.  Http requires some kludgery on the\n\tserver (see git-update-server-info), but it works.\n  git-ssh-fetch\n\tDo a fetch via ssh.\ngit-ls-remote.sh\n\tShow the contents of the refs/heads/ and/or refs/tags/ directories\n\tof a remote repository.  Useful to see what's available.\n  git-peek-remote\n\tHelper C program for the git-ls-remote script.  Implements the\n\tgit protocol form of it.\ngit-parse-remote.sh\n\tHelper script to parse a .git/remotes/ file.  Used by a number\n\tof these programs.\ngit-pull.sh\n\tFetches specific commits from the given remote repository,\n\tand merges everything into the current branch.\tIf a remote\n\tcommit is named as src:dst, this merges the remote head \"src\"\n\tinto the branch \"dst\" as well as the trunk.  Typically, the \"dst\"\n\tbranch is not modified locally, but is kept as a pristine copy\n\tof the remote branch.\n\n\tOne very standard example of this contention is that\n\ta repository that is tracking another specifies \"master:origin\"\n\tto provide a pristine local copy of the remote \"master\"\n\tbranch in the local branch named \"origin\".\n  git-ssh-pull\n\tA helper program that pulls over ssh.\ngit-shell\n\tA shell that can be used for git-only users.  Allows git\n\tpush (git-receive-pack) and pull (git-upload-pack) only.\n  git-receive-pack\n\tReceive a pack from git-send-pack, validate it, and add it to\n\tthe repository.  Adding just the bare objects has no security\n\timplications, but this can also update branches and tags, which\n\tdoes have an effect.\n\tRuns pre-update and post-update hooks; the former may do\n\tpermissions checking and disallow the upload.\n\tThis is the command run remotely via ssh by git-push.\n\n+ Publishing changes by network\ngit-daemon\n\tA daemon that serves up the git native protocol so anonymous\n\tclients can fetch data.  For it to allow export of a directory,\n\tthe magic file name \"git-daemon-export-ok\" must exist in it.\n\n\tThis does not accept (receive) data under any circumstances.\ngit-push.sh\n\tGit-pull, only backwards.  Send local changes to a remote\n\trepository.  The same .git/remotes/ short-cuts can be used,\n\tand the same src:dst syntax.  (But this time, the src is local\n\tand the dst is remote.)\n  git-http-push\n\tA helper to git-push to implement the http: protocol.\n  git-ssh-push\n\tA helper to git-push to push over ssh.\n  git-ssh-upload\n\tAnother helper.  This just does the equivalent of \"fetch\"\n\t(\"throw\"?) and doesn't actually merge the result.  Obsolete?\ngit-request-pull.sh\n\tGenerate an e-mail summarizing the changes between two commits,\n\tand request that the recipient pull them from your repository.\n\tJust a little helper to generate a consistent and informative\n\tformat.\ngit-send-pack\n\tPack together a pile of objects missing at the destination and\n\tsend them.  This is the sending half that talks to a remote\n\tgit-receive-pack.\ngit-update-server-info\n\tTo run git over http, auxiliary info files are required that\n\tdescribes what objects are in the repository (since git-upload-pack\n\tcan't generate this on the fly).  If you want to publish a\n\trepository via http, run this after every commit.  (Typically\n\tvia the hooks/post-update script.)\ngit-upload-pack\n\tLike git-send-pack, but this is invoked by a remote git-fetch-pack.\n"},{"id":"13367","messageId":"7vk6efb6ib.fsf@assigned-by-dhcp.cox.net","threadId":"2704","inReplyTo":"20051208063409.31967.qmail@science.horizon.com","subject":"Re: as promised, docs: git for the confused","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2005-12-08T21:53:16Z","receivedAt":"2005-12-08T21:53:16Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"linux@horizon.com writes:\n\n> * Terminology - heads, branches, refs, and revisions\n>\n> (This is a supplement to what's already in \"man git\".)\n>\n> The most common object needed by git primitives is a tree.  Since a\n> commit points to a tree and a tag points to a commit, both of these are\n> acceptable \"tree-ish\" objects and can be used interchangeably.  Likewise,\n> a tag is \"commit-ish\" and can be used where a commit is required.\n\nI am unsure if we want to further confuse readers by saying\nthis, but technically, \"Likewise, a tag which is commit-ish can\nbe used in place of commit\".  Not all tags are necessarily\ncommit-ish.  v2.6.11 tag is tree-ish but not commit-ish for\nexample.  Typically, however, a tag is commit-ish.\n"},{"id":"13368","messageId":"4398AD5D.7010101@zytor.com","threadId":"2704","inReplyTo":"7vk6efb6ib.fsf@assigned-by-dhcp.cox.net","subject":"Re: as promised, docs: git for the confused","fromName":"H. Peter Anvin","fromEmail":"hpa@zytor.com","sentAt":"2005-12-08T22:02:05Z","receivedAt":"2005-12-08T22:02:05Z","isPatch":false,"sender":{"key":"hpa@zytor.com","avatar":null},"body":"Junio C Hamano wrote:\n> linux@horizon.com writes:\n> \n> \n>>* Terminology - heads, branches, refs, and revisions\n>>\n>>(This is a supplement to what's already in \"man git\".)\n>>\n>>The most common object needed by git primitives is a tree.  Since a\n>>commit points to a tree and a tag points to a commit, both of these are\n>>acceptable \"tree-ish\" objects and can be used interchangeably.  Likewise,\n>>a tag is \"commit-ish\" and can be used where a commit is required.\n> \n> \n> I am unsure if we want to further confuse readers by saying\n> this, but technically, \"Likewise, a tag which is commit-ish can\n> be used in place of commit\".  Not all tags are necessarily\n> commit-ish.  v2.6.11 tag is tree-ish but not commit-ish for\n> example.  Typically, however, a tag is commit-ish.\n> \n\nSaying they can be used interchangably is just plain wrong, however. \nIt's not a bijective relation.\n\nSomething like:\n\n >> The most common object needed by git primitives is a tree.  Since a\n >> commit points and tags uniquely identify a tree, a commit or tag can\n >> be used anywhere a tree is expected.\n\n >> Likewise, most tags point to commits and can be used anywhere a\n >> commit is expected.\n\n... might be better, and avoids the colloquialisms.\n\n\t-hpa\n"},{"id":"13396","messageId":"200512090047.56754.alan@chandlerfamily.org.uk","threadId":"2704","inReplyTo":"20051208063409.31967.qmail@science.horizon.com","subject":"Re: as promised, docs: git for the confused","fromName":"Alan Chandler","fromEmail":"alan@chandlerfamily.org.uk","sentAt":"2005-12-09T00:47:56Z","receivedAt":"2005-12-09T00:47:56Z","isPatch":false,"sender":{"key":"alan@chandlerfamily.org.uk","avatar":"https://gravatar.com/avatar/1862247e5ea8eac114c842f9dc3a5db6253754e24ef7171757cf97eedce48b8c?d=mp&s=160"},"body":"On Thursday 08 Dec 2005 06:34, linux@horizon.com wrote:\n> As I mentioned with all my questions, I was writing up the answers\n> I got.  Here's the current status.  If anyone would like to comment on\n> its accuracy or usefulness, feedback is appreciated.\n...\n> * Background material.\n>\n> To start with, read \"man git\".  Or Documentation/git.txt in the git\n> source tree, which is the same thing.  Particularly note the description\n> of the index, which is where all the action in git happens.\n>\n> One thing that's confusing is why git allows you to have one version of\n> a file in the current HEAD, a second version in the index, and possibly a\n> third in the working directory.  Why doesn't the index just contain a copy\n> of the current HEAD until you commit a new one?  The answer is merging,\n> which does all its work in the index.  Neither the object database nor\n> the working directory let you have multiple files with the same name.\n\n\nIf I was a complete newbie, I would be lost right here.  You start refering to \nthe term HEAD without any introduction to what it means and (as far as I \ncould see on a quick glance - which is what a newbie would do - man git \ndoesn't start out here either).\n\nIf your audience really is a complete new commer, then as a minimum I think \nyou need  to describe to concept of a \"branch of development\" with a series \nof snapshots of the state, the current of which is called HEAD.  You might \neven at this stage hint about there being several such branches.  The next \nbit, which goes on about the index is great - just put it into context with a \nsimple explanation first.\n-- \nAlan Chandler\nhttp://www.chandlerfamily.org.uk\nOpen Source. It's the difference between trust and antitrust.\n"},{"id":"13398","messageId":"200512090219.38297.Josef.Weidendorfer@gmx.de","threadId":"2704","inReplyTo":"20051208063409.31967.qmail@science.horizon.com","subject":"Re: as promised, docs: git for the confused","fromName":"Josef Weidendorfer","fromEmail":"josef.weidendorfer@gmx.de","sentAt":"2005-12-09T01:19:38Z","receivedAt":"2005-12-09T01:19:38Z","isPatch":false,"sender":{"key":"josef.weidendorfer@gmx.de","avatar":null},"body":"On Thursday 08 December 2005 07:34, you wrote:\n> As I mentioned with all my questions, I was writing up the answers\n> I got.  Here's the current status.  If anyone would like to comment on\n> its accuracy or usefulness, feedback is appreciated.\n> ...\n\n> + Oddballs\n> git-mv.perl\n> \tI have to admit, I'm not quite sure what advantages this is\n> \tsupposed to have over plain \"mv\" followed by \"git-update-index\",\n> \tor why it's complex enough to need perl.\n> \n> \tBasically, this renames a file, deleting its old name and adding\n> \tits new name to the index.  Otherwise, it's a two-step process\n> \tto rename a file:\n> \t- Rename the file\n> \t- git-add the new name\n> \tFollowed by which you must commit both the old and new names\n\nThe nice thing about it is that you can move huge directories around,\nor multiple files/dirs at once, and it will do the right thing. E.g.\n\tgit-mv -k foo* bar/\nwill only move files which are version controlled.\n\nIt is actually a 3-step process: rename, delete old, add new.\nPerhaps it should be noted that this has nothing to do with any\nexplicit renaming feature like in other SCMs.\n\nJosef\n"},{"id":"13399","messageId":"20051209014520.GQ22159@pasky.or.cz","threadId":"2704","inReplyTo":"200512090047.56754.alan@chandlerfamily.org.uk","subject":"Re: as promised, docs: git for the confused","fromName":"Petr Baudis","fromEmail":"pasky@suse.cz","sentAt":"2005-12-09T01:45:20Z","receivedAt":"2005-12-09T01:45:20Z","isPatch":false,"sender":{"key":"pasky@ucw.cz","avatar":"https://avatars.githubusercontent.com/u/18439?v=4"},"body":"Dear diary, on Fri, Dec 09, 2005 at 01:47:56AM CET, I got a letter\nwhere Alan Chandler <alan@chandlerfamily.org.uk> said that...\n> On Thursday 08 Dec 2005 06:34, linux@horizon.com wrote:\n> > As I mentioned with all my questions, I was writing up the answers\n> > I got.  Here's the current status.  If anyone would like to comment on\n> > its accuracy or usefulness, feedback is appreciated.\n> ...\n> > * Background material.\n> >\n> > To start with, read \"man git\".  Or Documentation/git.txt in the git\n> > source tree, which is the same thing.  Particularly note the description\n> > of the index, which is where all the action in git happens.\n> >\n> > One thing that's confusing is why git allows you to have one version of\n> > a file in the current HEAD, a second version in the index, and possibly a\n> > third in the working directory.  Why doesn't the index just contain a copy\n> > of the current HEAD until you commit a new one?  The answer is merging,\n> > which does all its work in the index.  Neither the object database nor\n> > the working directory let you have multiple files with the same name.\n> \n> \n> If I was a complete newbie, I would be lost right here.  You start refering to \n> the term HEAD without any introduction to what it means and (as far as I \n> could see on a quick glance - which is what a newbie would do - man git \n> doesn't start out here either).\n\nI think that the first paragraph of the background material means\n\"insert Documentation/git.txt here\", the second one is then \"now what\nmight've been unclear there\".\n\nThat said, the \"git for the confused\" contains a lot of nice points, but\nI don't think it's a good approach to just have extra document for\nclarifying this stuff. It would be much better if the stock\ndocumentation itself would not be confusing in the first place. Same\ngoes for the \"commands overview\" (BOUND to get out-of-date over time\nsince it's detached from the normal per-command documentation; we have\ntroubles huge enough to keep usage strings in sync, let alone the\nmanpages).\n\n-- \n\t\t\t\tPetr \"Pasky\" Baudis\nStuff: http://pasky.or.cz/\nVI has two modes: the one in which it beeps and the one in which\nit doesn't.\n"}]}