{"thread":{"id":"1399","subject":"Users of git-check-files?","startedAt":"2005-08-02T23:10:45Z","lastAt":"2005-08-04T21:10:56Z","messageCount":37,"participants":["Johannes Schindelin","Linus Torvalds","Junio C Hamano","Josef Weidendorfer"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"6731","messageId":"Pine.LNX.4.63.0508030109210.21304@wgmdd8.biozentrum.uni-wuerzburg.de","threadId":"1399","inReplyTo":null,"subject":"Users of git-check-files?","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2005-08-02T23:10:45Z","receivedAt":"2005-08-02T23:10:45Z","isPatch":false,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi,\n\nthere's git-check-files in the repository, but AFAIK nobody uses it, not \neven \"git status\", which would be the primary candidate. If really no \nusers of git-check-files exist, maybe we should remove it?\n\nCiao,\nDscho\n"},{"id":"6739","messageId":"Pine.LNX.4.58.0508021942500.3341@g5.osdl.org","threadId":"1399","inReplyTo":"Pine.LNX.4.63.0508030109210.21304@wgmdd8.biozentrum.uni-wuerzburg.de","subject":"Re: Users of git-check-files?","fromName":"Linus Torvalds","fromEmail":"torvalds@osdl.org","sentAt":"2005-08-03T02:43:51Z","receivedAt":"2005-08-03T02:43:51Z","isPatch":false,"sender":{"key":"torvalds@linux-foundation.org","avatar":"https://avatars.githubusercontent.com/u/1024025?v=4"},"body":"\n\nOn Wed, 3 Aug 2005, Johannes Schindelin wrote:\n> \n> there's git-check-files in the repository, but AFAIK nobody uses it, not \n> even \"git status\", which would be the primary candidate. If really no \n> users of git-check-files exist, maybe we should remove it?\n\nYes.\n\nIt was used by the old \"git-applymbox\" (aka \"dotest\") until I got around \nwriting \"git-apply\".\n\nIt has no point any more, all the tools check the file status on their \nown, and yes, the thing should probably be removed.\n\n\t\tLinus\n"},{"id":"6742","messageId":"7vvf2nk0h7.fsf@assigned-by-dhcp.cox.net","threadId":"1399","inReplyTo":"Pine.LNX.4.58.0508021942500.3341@g5.osdl.org","subject":"Re: Users of git-check-files?","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2005-08-03T06:17:56Z","receivedAt":"2005-08-03T06:17:56Z","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> It has no point any more, all the tools check the file status on their \n> own, and yes, the thing should probably be removed.\n\nHow about git-rev-tree?  Does anybody care?\n"},{"id":"6750","messageId":"Pine.LNX.4.63.0508031618500.23728@wgmdd8.biozentrum.uni-wuerzburg.de","threadId":"1399","inReplyTo":"7vvf2nk0h7.fsf@assigned-by-dhcp.cox.net","subject":"Re: Users of git-check-files?","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2005-08-03T14:21:13Z","receivedAt":"2005-08-03T14:21:13Z","isPatch":false,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi,\n\nOn Tue, 2 Aug 2005, Junio C Hamano wrote:\n\n> Linus Torvalds <torvalds@osdl.org> writes:\n>\n>> It has no point any more, all the tools check the file status on their\n>> own, and yes, the thing should probably be removed.\n>\n> How about git-rev-tree?  Does anybody care?\n\nI try to write a \"git annotate\" based on the output of git-whatchanged. \nSince git-whatchanged only shows the commit and its parent, I need to \nfigure out what was the last diff that led to the current commit's state. \nThis needs git-rev-tree.\n\nCiao,\nDscho\n\nP.S.: My only unsolved problem is that git-whatchanged sometimes shows\nthe diffs in the wrong order (clock-skew problem?)\n"},{"id":"6751","messageId":"Pine.LNX.4.58.0508030808530.3341@g5.osdl.org","threadId":"1399","inReplyTo":"7vvf2nk0h7.fsf@assigned-by-dhcp.cox.net","subject":"Re: Users of git-check-files?","fromName":"Linus Torvalds","fromEmail":"torvalds@osdl.org","sentAt":"2005-08-03T15:09:32Z","receivedAt":"2005-08-03T15:09:32Z","isPatch":false,"sender":{"key":"torvalds@linux-foundation.org","avatar":"https://avatars.githubusercontent.com/u/1024025?v=4"},"body":"\n\nOn Tue, 2 Aug 2005, Junio C Hamano wrote:\n> \n> How about git-rev-tree?  Does anybody care?\n\nYeah, probably not. git-rev-list does so much more than git-rev-tree ever \ndid.\n\n\t\tLinus\n"},{"id":"6753","messageId":"7vr7dbhvci.fsf@assigned-by-dhcp.cox.net","threadId":"1399","inReplyTo":"Pine.LNX.4.58.0508030808530.3341@g5.osdl.org","subject":"Re: Users of git-check-files?","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2005-08-03T15:51:41Z","receivedAt":"2005-08-03T15:51:41Z","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> Yeah, probably not. git-rev-list does so much more than git-rev-tree ever \n> did.\n\nDoes rev-list do --edges ;-)?\n\nBTW, I have two known bugs/problems that I haven't resolved,\nwhich is bothering me quite a bit.  Yes, it is my fault (lack of\ntime and concentration).  One is the EINTR from the daemon.c,\nand another is receive-pack failing with \"unpack should have\ngenerated but I cannot find it\" when pushing.  The latter is\nsomething \"I am aware of, I know it needs to be diagnosed, but I\nhave not looked into yet\".\n"},{"id":"6754","messageId":"Pine.LNX.4.58.0508030913060.3341@g5.osdl.org","threadId":"1399","inReplyTo":"7vr7dbhvci.fsf@assigned-by-dhcp.cox.net","subject":"Re: Users of git-check-files?","fromName":"Linus Torvalds","fromEmail":"torvalds@osdl.org","sentAt":"2005-08-03T16:17:22Z","receivedAt":"2005-08-03T16:17:22Z","isPatch":false,"sender":{"key":"torvalds@linux-foundation.org","avatar":"https://avatars.githubusercontent.com/u/1024025?v=4"},"body":"\n\nOn Wed, 3 Aug 2005, Junio C Hamano wrote:\n>\n> Linus Torvalds <torvalds@osdl.org> writes:\n> \n> > Yeah, probably not. git-rev-list does so much more than git-rev-tree ever \n> > did.\n> \n> Does rev-list do --edges ;-)?\n\nNo, but does anybody use it? It _may_ be interesting as a git-merge-base\nthing, but then we should probably add it to git-merge-base (which\nactually _does_ do edges these days, but it just only shows the most\nrecent one..)\n\n> BTW, I have two known bugs/problems that I haven't resolved,\n> which is bothering me quite a bit.  Yes, it is my fault (lack of\n> time and concentration).  One is the EINTR from the daemon.c,\n\nI actually think the new code is totally broken. If you want to listen to \nseveral sockets, you should just run several daemons. Yeah, yeah, it won't \ngive you \"global child control\" etc, but I doubt we care.\n\nBut I don't think it's a huge issue, since most serious users are likely \nto use the \"--inetd\" flag and use inetd as the real daemon anyway (ie the \nbuilt-in daemon code is most useful for normal users just setting up \ntheir own quick thing).\n\n> and another is receive-pack failing with \"unpack should have\n> generated but I cannot find it\" when pushing.  The latter is\n> something \"I am aware of, I know it needs to be diagnosed, but I\n> have not looked into yet\".\n\nI've lost that state. Can you explain a bit mroe..\n\n\t\tLinus\n"},{"id":"6755","messageId":"7vk6j3f044.fsf@assigned-by-dhcp.cox.net","threadId":"1399","inReplyTo":"Pine.LNX.4.58.0508030913060.3341@g5.osdl.org","subject":"Re: Users of git-check-files?","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2005-08-03T16:36:59Z","receivedAt":"2005-08-03T16:36:59Z","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> I've lost that state. Can you explain a bit mroe..\n\nSorry, you have not lost anything.  It is my bad that this is\nthe first time I brought it up.  I've been seeing that from time\nto time when I push to either my \"send to master\" repository\nfrom my working repository, or from the \"send to master\"\nrepository to master.kernel.org, but I haven't figured it out if\nthere is any pattern.  It's one of those \"I'll try to take a\nsnapshot so I can have a reproduction recipe to figure it out\nnext time it happens\" things.  Unfortunately, when it happens\nagainst master.kernel.org, I have more urgent task of making\nsure that the public repository is not in any way corrupted, and\nafter fixing that (it typically takes removing the\ngit.git/refs/{master,pu} and repushing, which recovers fine), I\ndo not have much to start trying to reproduce it anymore X-<.\n"},{"id":"6757","messageId":"Pine.LNX.4.58.0508030944210.3258@g5.osdl.org","threadId":"1399","inReplyTo":"7vk6j3f044.fsf@assigned-by-dhcp.cox.net","subject":"Re: Users of git-check-files?","fromName":"Linus Torvalds","fromEmail":"torvalds@osdl.org","sentAt":"2005-08-03T16:45:12Z","receivedAt":"2005-08-03T16:45:12Z","isPatch":false,"sender":{"key":"torvalds@linux-foundation.org","avatar":"https://avatars.githubusercontent.com/u/1024025?v=4"},"body":"\n\nOn Wed, 3 Aug 2005, Junio C Hamano wrote:\n>\n> Linus Torvalds <torvalds@osdl.org> writes:\n> \n> > I've lost that state. Can you explain a bit mroe..\n> \n> Sorry, you have not lost anything.  It is my bad that this is\n> the first time I brought it up.  I've been seeing that from time\n> to time when I push to either my \"send to master\" repository\n> from my working repository, or from the \"send to master\"\n> repository to master.kernel.org, but I haven't figured it out if\n> there is any pattern.\n\nAre you sure you have a good git version on master? I've never seen \nanything like that, and I push all the time..\n\n\t\tLinus\n"},{"id":"6756","messageId":"Pine.LNX.4.63.0508031845001.24273@wgmdd8.biozentrum.uni-wuerzburg.de","threadId":"1399","inReplyTo":"7vk6j3f044.fsf@assigned-by-dhcp.cox.net","subject":"Re: Users of git-check-files?","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2005-08-03T16:46:41Z","receivedAt":"2005-08-03T16:46:41Z","isPatch":false,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi,\n\nOn Wed, 3 Aug 2005, Junio C Hamano wrote:\n\n> Sorry, you have not lost anything.  It is my bad that this is\n> the first time I brought it up.  I've been seeing that from time\n> to time when I push to either my \"send to master\" repository\n> from my working repository, or from the \"send to master\"\n> repository to master.kernel.org, but I haven't figured it out if\n> there is any pattern.\n\nThis could be related to what I was realizing the other day: when trying \nto push to a repository (just one branch), but I do not have _all_ of the \nremote branches pulled, then it fails.\n\nCiao,\nDscho\n"},{"id":"6758","messageId":"Pine.LNX.4.63.0508031849270.24318@wgmdd8.biozentrum.uni-wuerzburg.de","threadId":"1399","inReplyTo":"Pine.LNX.4.58.0508030944210.3258@g5.osdl.org","subject":"Re: Users of git-check-files?","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2005-08-03T16:50:22Z","receivedAt":"2005-08-03T16:50:22Z","isPatch":false,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi,\n\nOn Wed, 3 Aug 2005, Linus Torvalds wrote:\n\n> Are you sure you have a good git version on master? I've never seen\n> anything like that, and I push all the time..\n\nCall him Zaphod: he has two heads (master and pu). You don't. As I said in \nanother mail, this could be very well related to Junio's problems.\n\nCiao,\nDscho\n"},{"id":"6759","messageId":"7voe8fdkd7.fsf@assigned-by-dhcp.cox.net","threadId":"1399","inReplyTo":"Pine.LNX.4.58.0508030944210.3258@g5.osdl.org","subject":"Re: Users of git-check-files?","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2005-08-03T17:02:28Z","receivedAt":"2005-08-03T17:02:28Z","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> Are you sure you have a good git version on master? I've never seen \n> anything like that, and I push all the time..\n\nI have been esuspecting that it happens only because I rewind\nand rebase \"pu\", which you never do.  The thing is, even though\nI rewind \"pu\" all the time, it happens only occasionally.\n"},{"id":"6761","messageId":"200508031908.22562.Josef.Weidendorfer@gmx.de","threadId":"1399","inReplyTo":"Pine.LNX.4.63.0508031849270.24318@wgmdd8.biozentrum.uni-wuerzburg.de","subject":"Re: Users of git-check-files?","fromName":"Josef Weidendorfer","fromEmail":"josef.weidendorfer@gmx.de","sentAt":"2005-08-03T17:08:22Z","receivedAt":"2005-08-03T17:08:22Z","isPatch":false,"sender":{"key":"josef.weidendorfer@gmx.de","avatar":null},"body":"On Wednesday 03 August 2005 18:50, you wrote:\n> Hi,\n>\n> On Wed, 3 Aug 2005, Linus Torvalds wrote:\n> > Are you sure you have a good git version on master? I've never seen\n> > anything like that, and I push all the time..\n>\n> Call him Zaphod: he has two heads (master and pu). You don't. As I said in\n> another mail, this could be very well related to Junio's problems.\n\nYes it is. To reproduce:\nCreate a repository with 2 branches.\nMake 2 clones of the 2 branches via SSH.\nMake a commit on one clone and push.\nMake another commit on the other clone and push => ERROR\n\nA log of this last push:\n=============================================\n~/tmp/git/clone2> cg-push\n'refs/heads/branch2': updating from 80e4d426dd4c865b943cc1121b580a946eee921d \nto 8196067677e3415ce404ea5bc35731ac7d56115d\nfatal: bad object f7e944b036fd00af656b262140c1dc93ceffadb1\nPacking 0 objects\nUnpacking 0 objects\n\nfatal: unpack should have generated 8196067677e3415ce404ea5bc35731ac7d56115d, \nbut I can't find it!\n=============================================\n\nf7e9... is the commit pushed from the first clone.\n\nI had the same problem yesterday.\n\nJosef\n"},{"id":"6763","messageId":"Pine.LNX.4.58.0508031014070.3258@g5.osdl.org","threadId":"1399","inReplyTo":"7voe8fdkd7.fsf@assigned-by-dhcp.cox.net","subject":"Re: Users of git-check-files?","fromName":"Linus Torvalds","fromEmail":"torvalds@osdl.org","sentAt":"2005-08-03T17:23:14Z","receivedAt":"2005-08-03T17:23:14Z","isPatch":false,"sender":{"key":"torvalds@linux-foundation.org","avatar":"https://avatars.githubusercontent.com/u/1024025?v=4"},"body":"\n\nOn Wed, 3 Aug 2005, Junio C Hamano wrote:\n>\n> Linus Torvalds <torvalds@osdl.org> writes:\n> \n> > Are you sure you have a good git version on master? I've never seen \n> > anything like that, and I push all the time..\n> \n> I have been esuspecting that it happens only because I rewind\n> and rebase \"pu\", which you never do.  The thing is, even though\n> I rewind \"pu\" all the time, it happens only occasionally.\n\nOh, that would do it. \n\nYou need to prune back the remote tree you send to, so that it is a real\nsubset of what you are sending from (at least as far as the branch you\nsend is concerned - other branches may be ahead of you, of course). Unlike\n\"git-fetch-pack\", the send-pack interface does not do any common commit\ndiscovery, so if you have state on the other end that isn't on your local\nend, that's setting yourself up for problems: you are basically misusing\nthe interfaces.\n\nI started out to make the \"-f\" flag to send-file work around it, but I\nnever finished that, partly because it really ends up being the same thing\nas \"git-fetch-pack\" in reverse, which was against the whole point of\ngit-send-pack. Send-pack is meant to be an \"update remote tree\" thing, \nwith the assumption that the remote tree is a subset - and exactly that \nassumption is what makes send-pack much cheaper than fetch-pack.\n\n(Actually, to me it's not the \"cheaper\" that matters, but exactly the fact\nthat send-pack is so safe - if somebody has changed something at the other \nend that I don't have in mine, I _want_ errors, because that would be a \nserious problem).\n\n\t\tLinus\n"},{"id":"6764","messageId":"7vy87jc4ia.fsf@assigned-by-dhcp.cox.net","threadId":"1399","inReplyTo":"200508031908.22562.Josef.Weidendorfer@gmx.de","subject":"Re: Users of git-check-files?","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2005-08-03T17:30:21Z","receivedAt":"2005-08-03T17:30:21Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Josef Weidendorfer <Josef.Weidendorfer@gmx.de> writes:\n\n> ~/tmp/git/clone2> cg-push\n> 'refs/heads/branch2': updating from 80e4d426dd4c865b943cc1121b580a946eee921d \n> to 8196067677e3415ce404ea5bc35731ac7d56115d\n> fatal: bad object f7e944b036fd00af656b262140c1dc93ceffadb1\n> Packing 0 objects\n> Unpacking 0 objects\n\nAhhhh.\n\nYes, we read from the remote and use old->sha1 when doing the\npack generation.  If we do not have that object (in Josef's\nexample because it is not something we have pulled yet), then\nrev-list has no way to create the necessary pack.\n\nI have a feeling this explains what I've been seeing as well.\nThe first thing I do before I push is to fetch (but not\nmerge-pull) from kernel.org, but this happens against\nwww.kernel.org (to make sure people are seeing what I want them\nto see), not against master.  So if I happen to do my push cycle\ntwice before the things propagate from master to www.kernel.org,\n_and_ if I happened to have run git prune in my private\nrepository just before the second cycle, I may end up not having\nthe objects referenced by \"pu\" branch there in my private\nrepository.\n"},{"id":"6765","messageId":"7virymdirb.fsf@assigned-by-dhcp.cox.net","threadId":"1399","inReplyTo":"Pine.LNX.4.58.0508031014070.3258@g5.osdl.org","subject":"Re: Users of git-check-files?","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2005-08-03T17:37:12Z","receivedAt":"2005-08-03T17:37:12Z","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> I started out to make the \"-f\" flag to send-file work around it, but I\n> never finished that, partly because it really ends up being the same thing\n> as \"git-fetch-pack\" in reverse, which was against the whole point of\n> git-send-pack. Send-pack is meant to be an \"update remote tree\" thing, \n> with the assumption that the remote tree is a subset - and exactly that \n> assumption is what makes send-pack much cheaper than fetch-pack.\n\nI think in addition to the existing ref_newer() check, which\nmakes sure you are advancing the remote head, not just replacing\nwith something unrelated, making sure that we have objects\nreferenced by ref->old_sha1 we obtained from the remote on our\nend for all branches involved would be the only thing needed.\nThe latter the users should not even be able to override with\nthe --force flag, of course, but we would remind them to pull\nfrom the other end first.\n"},{"id":"6766","messageId":"200508031946.01017.Josef.Weidendorfer@gmx.de","threadId":"1399","inReplyTo":"7virymdirb.fsf@assigned-by-dhcp.cox.net","subject":"Re: Users of git-check-files?","fromName":"Josef Weidendorfer","fromEmail":"josef.weidendorfer@gmx.de","sentAt":"2005-08-03T17:46:00Z","receivedAt":"2005-08-03T17:46:00Z","isPatch":false,"sender":{"key":"josef.weidendorfer@gmx.de","avatar":null},"body":"On Wednesday 03 August 2005 19:37, you wrote:\n> Linus Torvalds <torvalds@osdl.org> writes:\n> > I started out to make the \"-f\" flag to send-file work around it, but I\n> > never finished that, partly because it really ends up being the same\n> > thing as \"git-fetch-pack\" in reverse, which was against the whole point\n> > of git-send-pack. Send-pack is meant to be an \"update remote tree\" thing,\n> > with the assumption that the remote tree is a subset - and exactly that\n> > assumption is what makes send-pack much cheaper than fetch-pack.\n>\n> I think in addition to the existing ref_newer() check, which\n> makes sure you are advancing the remote head, not just replacing\n> with something unrelated, making sure that we have objects\n> referenced by ref->old_sha1 we obtained from the remote on our\n> end for all branches involved would be the only thing needed.\n> The latter the users should not even be able to override with\n> the --force flag, of course, but we would remind them to pull\n> from the other end first.\n\nBut my example shows that the error happens even with 2 branches totally \nunrelated to each other: if branch1 got a new commit, you can not push to\nbranch2 from another clone.\n\nWhy is it not enough to have all the history of a remote branch in the local \nclone to be able to push to this branch?\n\nJosef\n"},{"id":"6768","messageId":"200508031946.50172.Josef.Weidendorfer@gmx.de","threadId":"1399","inReplyTo":"200508031908.22562.Josef.Weidendorfer@gmx.de","subject":"Re: Users of git-check-files?","fromName":"Josef Weidendorfer","fromEmail":"josef.weidendorfer@gmx.de","sentAt":"2005-08-03T17:46:50Z","receivedAt":"2005-08-03T17:46:50Z","isPatch":false,"sender":{"key":"josef.weidendorfer@gmx.de","avatar":null},"body":"On Wednesday 03 August 2005 19:08, you wrote:\n> Yes it is. To reproduce:\n\nYou do not need 2 clones.\nIt is enough to have one clone with a branch, and you make a commit in the \noriginal repository.\nAfterwards, pushing a new commit from the clone gives the error.\n\nAfter pulling the missing commit from the original rep, the push works.\n\nJosef\n"},{"id":"6769","messageId":"Pine.LNX.4.58.0508031048360.3258@g5.osdl.org","threadId":"1399","inReplyTo":"7virymdirb.fsf@assigned-by-dhcp.cox.net","subject":"Re: Users of git-check-files?","fromName":"Linus Torvalds","fromEmail":"torvalds@osdl.org","sentAt":"2005-08-03T17:48:49Z","receivedAt":"2005-08-03T17:48:49Z","isPatch":false,"sender":{"key":"torvalds@linux-foundation.org","avatar":"https://avatars.githubusercontent.com/u/1024025?v=4"},"body":"\n\nOn Wed, 3 Aug 2005, Junio C Hamano wrote:\n> \n> I think in addition to the existing ref_newer() check, which\n> makes sure you are advancing the remote head, not just replacing\n> with something unrelated, making sure that we have objects\n> referenced by ref->old_sha1 we obtained from the remote on our\n> end for all branches involved would be the only thing needed.\n\nYes.\n\n\t\tLinus\n"},{"id":"6770","messageId":"Pine.LNX.4.58.0508031055090.3258@g5.osdl.org","threadId":"1399","inReplyTo":"Pine.LNX.4.63.0508031618500.23728@wgmdd8.biozentrum.uni-wuerzburg.de","subject":"Re: Users of git-check-files?","fromName":"Linus Torvalds","fromEmail":"torvalds@osdl.org","sentAt":"2005-08-03T18:00:32Z","receivedAt":"2005-08-03T18:00:32Z","isPatch":false,"sender":{"key":"torvalds@linux-foundation.org","avatar":"https://avatars.githubusercontent.com/u/1024025?v=4"},"body":"\n\nOn Wed, 3 Aug 2005, Johannes Schindelin wrote:\n> \n> I try to write a \"git annotate\" based on the output of git-whatchanged. \n\nYou can't. It's fundamentally not doable, because you lose the merge \ninformation.\n\nSo you need to use a combination of git-rev-list _and_ git-whatchanged.\n\nUse the \"--parents\" flag to git-rev-list to get the parents output for \ndoing your own graph, if you want to.\n\nI have been thinking of adding a \"follow this file\" mode to git-rev-list,\nwhich just ignores all children of merges that used the file directly from\none of the other children. Exactly because then you could have a\ngit-rev-list that prunes based on filename, and would potentially be a lot\nmore efficient (not follow the \"uninteresting\" side of a merge).\n\nI haven't gotten around to it, partly because I wonder if it would be\nbetter as a separate program - even if that would mean that you'd lose all\nthe cool features of git-rev-list (the ability to limit it to certain\nversions, and the ability to sort the output in relevant orders).\n\nPartly because I'm just too friggin lazy.\n\n> P.S.: My only unsolved problem is that git-whatchanged sometimes shows\n> the diffs in the wrong order (clock-skew problem?)\n\nNope, this is a direct result of two branches modifying the same file in \nparallel. There is no \"right\" or \"wrong\" order.\n\n\t\tLinus\n"},{"id":"6771","messageId":"Pine.LNX.4.58.0508031101220.3258@g5.osdl.org","threadId":"1399","inReplyTo":"Pine.LNX.4.63.0508031849270.24318@wgmdd8.biozentrum.uni-wuerzburg.de","subject":"Re: Users of git-check-files?","fromName":"Linus Torvalds","fromEmail":"torvalds@osdl.org","sentAt":"2005-08-03T18:02:20Z","receivedAt":"2005-08-03T18:02:20Z","isPatch":false,"sender":{"key":"torvalds@linux-foundation.org","avatar":"https://avatars.githubusercontent.com/u/1024025?v=4"},"body":"\n\nOn Wed, 3 Aug 2005, Johannes Schindelin wrote:\n> \n> On Wed, 3 Aug 2005, Linus Torvalds wrote:\n> \n> > Are you sure you have a good git version on master? I've never seen\n> > anything like that, and I push all the time..\n> \n> Call him Zaphod: he has two heads (master and pu). You don't.\n\nOh, but I most definitely do. I update several heads at a time when I \ncreate a new tag etc.\n\nWhat I don't do is to rewrite my history, though..\n\n\t\tLinus\n"},{"id":"6772","messageId":"7vy87ic2sd.fsf@assigned-by-dhcp.cox.net","threadId":"1399","inReplyTo":"Pine.LNX.4.58.0508031048360.3258@g5.osdl.org","subject":"Re: Users of git-check-files?","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2005-08-03T18:07:30Z","receivedAt":"2005-08-03T18:07:30Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"This patch seems to fix the problem.\n\n * If the original value of remote ref refers to an object we do\n   not have, and if the ref is one of the branches we are trying\n   to push, we refuse to update it.\n\n * Otherwise, we do not attempt to use such an value when\n   computing what objects to put in pack, since rev-list would\n   fail.\n\nI've tested Josef's two-branches case, one repo updates one\nbranch and pushes to the central repo, another repo updates the\nother branch and pushed to the central repo.  The old code\nbarfed when invoking rev-list, but this does not seem to.\n\nJosef, could you give it a try please?\n\n---\ncd /opt/packrat/playpen/public/in-place/git/git.junio/\njit-diff\n# - master: git-send-email-script: minimum whitespace cleanup.\n# + (working tree)\ndiff --git a/send-pack.c b/send-pack.c\n--- a/send-pack.c\n+++ b/send-pack.c\n@@ -43,7 +43,8 @@ static void exec_rev_list(struct ref *re\n \t\tchar *buf = malloc(100);\n \t\tif (i > 900)\n \t\t\tdie(\"git-rev-list environment overflow\");\n-\t\tif (!is_zero_sha1(refs->old_sha1)) {\n+\t\tif (!is_zero_sha1(refs->old_sha1) &&\n+\t\t    has_sha1_file(refs->old_sha1)) {\n \t\t\targs[i++] = buf;\n \t\t\tsnprintf(buf, 50, \"^%s\", sha1_to_hex(refs->old_sha1));\n \t\t\tbuf += 50;\n@@ -208,6 +209,12 @@ static int send_pack(int in, int out, in\n \t\t\tcontinue;\n \t\t}\n \n+\t\tif (!has_sha1_file(ref->old_sha1)) {\n+\t\t\terror(\"remote '%s' object %s does not exist on local\",\n+\t\t\t      name, sha1_to_hex(ref->old_sha1));\n+\t\t\tcontinue;\n+\t\t}\n+\n \t\t/* Ok, mark it for update */\n \t\tmemcpy(ref->new_sha1, new_sha1, 20);\n \t}\n\nCompilation finished at Wed Aug  3 11:02:15\n"},{"id":"6773","messageId":"Pine.LNX.4.58.0508031102590.3258@g5.osdl.org","threadId":"1399","inReplyTo":"200508031908.22562.Josef.Weidendorfer@gmx.de","subject":"Re: Users of git-check-files?","fromName":"Linus Torvalds","fromEmail":"torvalds@osdl.org","sentAt":"2005-08-03T18:08:29Z","receivedAt":"2005-08-03T18:08:29Z","isPatch":false,"sender":{"key":"torvalds@linux-foundation.org","avatar":"https://avatars.githubusercontent.com/u/1024025?v=4"},"body":"\n\nOn Wed, 3 Aug 2005, Josef Weidendorfer wrote:\n> \n> Yes it is. To reproduce:\n> Create a repository with 2 branches.\n> Make 2 clones of the 2 branches via SSH.\n> Make a commit on one clone and push.\n> Make another commit on the other clone and push => ERROR\n\nThis works perfectly fine, you just have to make sure that you update the \nright head.\n\nIf you try to update a head that is ahead of you, that is driver error. \nAdmittedly one that could have nicer error messages ;)\n\nThis is why git-send-pack takes the name of the branch to update..\n\nThe real problem with git-send-pack is that the local and remote names \nhave to be the same, which is a bug, really. It _should_ be perfectly fine \nto do something like\n\n\tgit-send-pack ..dest.. localname:remotename\n\nwhich would push the local \"localname\" branch to the remote \"remotename\" \nbranch.\n\n\t\t\tLinus\n"},{"id":"6774","messageId":"Pine.LNX.4.58.0508031108550.3258@g5.osdl.org","threadId":"1399","inReplyTo":"200508031946.01017.Josef.Weidendorfer@gmx.de","subject":"Re: Users of git-check-files?","fromName":"Linus Torvalds","fromEmail":"torvalds@osdl.org","sentAt":"2005-08-03T18:10:14Z","receivedAt":"2005-08-03T18:10:14Z","isPatch":false,"sender":{"key":"torvalds@linux-foundation.org","avatar":"https://avatars.githubusercontent.com/u/1024025?v=4"},"body":"\n\nOn Wed, 3 Aug 2005, Josef Weidendorfer wrote:\n> \n> But my example shows that the error happens even with 2 branches totally \n> unrelated to each other: if branch1 got a new commit, you can not push to\n> branch2 from another clone.\n\nSure you can.\n\n\tgit-send-pack remote branch2\n\nand you've just done so.\n\nThe shorthand of \"no branches listed\" expands to _all_ branches, and if \nyou try to send all branches, then you're trying to update \"branch1\" with \nsomething you don't have. That's your usage error.\n\n\t\tLinus\n"},{"id":"6775","messageId":"200508032031.24257.Josef.Weidendorfer@gmx.de","threadId":"1399","inReplyTo":"7vy87ic2sd.fsf@assigned-by-dhcp.cox.net","subject":"Re: Users of git-check-files?","fromName":"Josef Weidendorfer","fromEmail":"josef.weidendorfer@gmx.de","sentAt":"2005-08-03T18:31:24Z","receivedAt":"2005-08-03T18:31:24Z","isPatch":false,"sender":{"key":"josef.weidendorfer@gmx.de","avatar":null},"body":"On Wednesday 03 August 2005 20:07, Junio C Hamano wrote:\n> Josef, could you give it a try please?\n\nPerfect. Thanks.\n\nJosef\n"},{"id":"6780","messageId":"Pine.LNX.4.63.0508032341320.31852@wgmdd8.biozentrum.uni-wuerzburg.de","threadId":"1399","inReplyTo":"Pine.LNX.4.58.0508031055090.3258@g5.osdl.org","subject":"Re: Users of git-check-files?","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2005-08-03T22:09:17Z","receivedAt":"2005-08-03T22:09:17Z","isPatch":false,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi,\n\nOn Wed, 3 Aug 2005, Linus Torvalds wrote:\n\n> On Wed, 3 Aug 2005, Johannes Schindelin wrote:\n>>\n>> I try to write a \"git annotate\" based on the output of git-whatchanged.\n>\n> You can't. It's fundamentally not doable, because you lose the merge\n> information.\n\nThat's why I said I need git-rev-tree. In the meantime I discovered, that \ngit-rev-list has a \"--parents\" option which suits me just fine. Therefore \nI'd say: kill git-rev-tree.\n\n> So you need to use a combination of git-rev-list _and_ git-whatchanged.\n\nI tried to do without the ugly \"script is calling script is calling \nprogram\" idiom. That is why my attempt at git-annotate (see attached) is \nso slow.\n\n> I have been thinking of adding a \"follow this file\" mode to git-rev-list,\n> which just ignores all children of merges that used the file directly from\n> one of the other children. Exactly because then you could have a\n> git-rev-list that prunes based on filename, and would potentially be a lot\n> more efficient (not follow the \"uninteresting\" side of a merge).\n\nLet's sit and see if people pick it up at all. If yes, I'd rather rewrite \nthe whole thing in C eventually (it is in perl now and uses hashes quite \nextensively...).\n\n>> P.S.: My only unsolved problem is that git-whatchanged sometimes shows\n>> the diffs in the wrong order (clock-skew problem?)\n>\n> Nope, this is a direct result of two branches modifying the same file in\n> parallel. There is no \"right\" or \"wrong\" order.\n\nExactly. But there is a \"you probably meant that\": the branch in which it \nwas modified last (not counting merges, of course).\n\nNotes:\n\n- You can either annotate by commit (this is the default), or show \nsome other informations with the \"-f\" flag: Try \"-f author,commit:8\".\n\n- If you don't specify any files, it assumes you mean all files \n(Attention: slow).\n\n- You can start at a commit instead of the current state by specifying\n\"-c other_commit\".\n\n- The list of commits is traversed as output by git-rev-list, i.e. \nchronologically. Each line is marked with the commit whose parent does not \ncontain that line.\n\n- I am not at all sure if my handling of merges is sane. The logic is like \nthis: If the commit is parent to more than one commit (i.e. a merge), then \nthe touched lines are tentatively marked as changed in that commit, but \nare possibly overridden at a later stage.\n\nCiao,\nDscho\n\n\n#!/usr/bin/perl\n\nuse Getopt::Std;\n\nsub usage() {\n\tprint STDERR 'Usage: ${\\basename $0} [-s] [-f format] [-c commit] [files...]\n\n\t-s\t\tonly look at first parent in case of a merge\n\t-f format\trevision format (e.g. \"author,commit:8\")\n\t-c commit\tstart looking at this commit\n';\n\n\texit(1);\n}\n\ngetopts(\"hsf:c:\") or usage();\n$opt_h && usage();\n\n$first_parent_only=$opt_s;\n\nsub read_file ($) {\n\tmy $file=$_[0];\n\topen IN, $file || return 1;\n\t$orig_line_count=0;\n\t@lines=();\n\t@line_handled=();\n\t@revisions=();\n\twhile(<IN>) {\n\t\t$orig_line_count++;\n\t\t$lines[$orig_line_count]=$_;\n\t}\n\tclose IN;\n\t$orig_line_count>0 || return 2;\n\t@mapping[1..$orig_line_count]=(1..$orig_line_count);\n\treturn 0;\n}\n\t\nsub init_file($$) {\n\tmy $file=$_[0];\n\tmy $head=$_[1];\n\n\tif($head eq \"\") {\n\t\t# read current file\n\t\tmy $ret=read_file(\"<\".$file);\n\t\t$ret==0 || return $ret;\n\n\t\t$current_revision=\"*\"x($revision_string_length-1).\";\";\n\t\thandle_diff(\"git-diff-files -p \".$file.\"|\",1);\n\t} else {\n\t\tif(`git-ls-tree $head $file`=~/^\\S+\\s+\\S+\\s+(\\S+)/) {\n\t\t\t$sha1=$1;\n\t\t\tmy $ret=read_file(\"git-cat-file blob \".$sha1.\"|\");\n\t\t\t$ret==0 || return $ret;\n\t\t} else {\n\t\t\tusage();\n\t\t}\n\t}\n\t$file_version=0;\n\treturn 0;\n}\n\n# mark all lines still unaccounted for\nsub mark_all ($) {\n\tmy $mark_lines_as_handled=$_[0];\n\tforeach $line (@mapping) {\n\t\tif($line_handled{$line}==undef) {\n\t\t\t$revisions[$line]=get_revision();\n\t\t\tif($mark_lines_as_handled) {\n\t\t\t\t$line_handled{$line}=1;\n\t\t\t}\n\t\t}\n\t}\n\tif($mark_lines_as_handled) {\n\t\t$orig_line_count=0;\n\t\t@mapping=();\n\t}\n}\n\n# this sub only handles unified diffs\nsub handle_diff($$) {\n\tmy $diff=$_[0];\n\tmy $mark_lines_as_handled=$_[1];\n\n\topen DIFF, $diff;\n\tmy @new_mapping=();\n\tmy $current_line_nr_minus=1;\n\tmy $current_line_nr_plus=1;\n\n\twhile(<DIFF>) {\n\t\tif(/^@@ -(\\d+),(\\d+) \\+(\\d+),(\\d+) @@/) {\n\t\t\t$empty_diff=0;\n\t\t\t$start_minus=$1;\n\t\t\t$count_minus=$2;\n\t\t\t$start_plus=$3;\n\t\t\t$count_plus=$4;\n\n\t\t\t# if file was created here, were finished\n\t\t\tif($start_minus==0) {\n\t\t\t\tmark_all($mark_lines_as_handled);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t# sane check\n\t\t\t$start_minus-$current_line_nr_minus==$start_plus-$current_line_nr_plus\n\t\t\t\t|| die \"invalid diff: $start_minus,$current_line_nr_minus,$start_plus,$current_line_nr_plus\";\n\t\t\tif($start_minus-$current_line_nr_minus>0) {\n\t\t\t\t@new_mapping[$current_line_nr_minus..$start_minus]\n\t\t\t\t\t=@mapping[$current_line_nr_plus..$start_plus];\n\t\t\t\t$current_line_nr_minus=$start_minus;\n\t\t\t\t$current_line_nr_plus=$start_plus;\n\t\t\t}\n\t\t\twhile($count_minus>0 || $count_plus>0) {\n\t\t\t\t$_=<DIFF>;\n\t\t\t\tif(/^-/) {\n\t\t\t\t\t$new_mapping[$current_line_nr_minus]=undef;\n\t\t\t\t\t$current_line_nr_minus++;\n\t\t\t\t\t$count_minus--;\n\t\t\t\t} else {\n\t\t\t\t\tif(/^\\+/) {\n\t\t\t\t\t\t$orig=$mapping[$current_line_nr_plus];\n\t\t\t\t\t\tif($orig>0 && $line_handled[$orig]==undef) {\n\t\t\t\t\t\t\t$revisions[$orig]=get_revision();\n\t\t\t\t\t\t\tif($mark_lines_as_handled) {\n\t\t\t\t\t\t\t\t$line_handled[$orig]=1;\n\t\t\t\t\t\t\t\t$orig_line_count--;\n\t\t\t\t\t\t\t\tif($orig_line_count==0) {\n\t\t\t\t\t\t\t\t\t@mapping=@new_mapping;\n\t\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\t$current_line_nr_plus++;\n\t\t\t\t\t\t$count_plus--;\n\t\t\t\t\t} else {\n\t\t\t\t\t\t$orig_line_nr=$mapping[$current_line_nr_plus];\n\t\t\t\t\t\t$new_mapping[$current_line_nr_minus]=$orig_line_nr;\n\t\t\t\t\t\tif($orig_line_nr>0) {\n\t\t\t\t\t\t\t# sane check\n\t\t\t\t\t\t\tif(substr($_,1) ne $lines[$orig_line_nr]) {\n\t\t\t\t\t\t\t\tprint \"--\\n\";\n\t\t\t\t\t\t\t\tprint @lines[($orig_line_nr-3)..($orig_line_nr+3)];\n\t\t\t\t\t\t\t\tprint \"--\\n\";\n\t\t\t\t\t\t\t\tdie \"invalid diff ($orig_line_nr:$current_line_nr_plus): \".substr($_,1).\" is not \".$lines[$orig_line_nr];\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tsubstr($_,1) eq $lines[$orig_line_nr] ||\n\t\t\t\t\t\t\t\tdie \"invalid diff ($diff): \".substr($_,1).\" is not \".$lines[$orig_line_nr].$lines[1..$#lines];\n\t\t\t\t\t\t}\n\t\t\t\t\t\t$current_line_nr_minus++;\n\t\t\t\t\t\t$current_line_nr_plus++;\n\t\t\t\t\t\t$count_minus--;\n\t\t\t\t\t\t$count_plus--;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\tclose DIFF;\n\t$rest_lines=$#mapping-$current_line_nr_plus;\n\tif($rest_lines>0) {\n\t\t@new_mapping[$current_line_nr_minus..($current_line_nr_minus+$rest_lines)]\n\t\t\t=@mapping[$current_line_nr_plus..($current_line_nr_plus+$rest_lines)];\n\t}\n\t$file_version++;\n\t@mapping=@new_mapping;\n\treturn;\n}\n\nsub get_revision() {\n\tif($current_revision eq \"\") {\n\t\t%commit_values=('fileversion','V-'.$file_version);\n\t\t$commit_values{'commit'}=$current_commit;\n\t\topen COMMIT, \"git-cat-file commit $current_commit|\";\n\t\twhile(($_=<COMMIT>) && !/^$/) {\n\t\t\tif(/^parent ([0-9a-f]{40})/) {\n\t\t\t\t$commit_values{'parents'}.=$1.\" \";\n\t\t\t} elsif(/^author (.*)/) {\n\t\t\t\t$commit_values{'author'}=$1;\n\t\t\t} elsif(/^committer (.*)/) {\n\t\t\t\t$commit_values{'committer'}=$1;\n\t\t\t}\n\t\t}\n\t\tclose COMMIT;\n\n\t\tfor($i=0;$i<$#revision_format;$i+=2) {\n\t\t\tmy $temp=$commit_values{$revision_format[$i]};\n\t\t\tmy $length=length($temp);\n\t\t\tif($length>$revision_format[$i+1]) {\n\t\t\t\t$temp=substr($temp,0,$revision_format[$i+1]);\n\t\t\t} elsif($length<$revision_format[$i+1]) {\n\t\t\t\t$temp.=\" \"x($revision_format[$i+1]-$length);\n\t\t\t}\n\t\t\t$current_revision.=$temp.\";\";\n\t\t}\n\t}\n\treturn $current_revision;\n}\n\nsub show_current {\n\tfor($i=1;$i<=$#lines;$i++) {\n\t\tprint $revisions[$i].$lines[$i];\n\t}\n}\n\nsub annotate_file($$) {\n\tmy $file=$_[0];\n\tmy $head=$_[1];\n\n\tinit_file($file,$head);\n\n\tmy @new_mapping=@mapping;\n\t%commit_mappings=($commits[0]=>\\@new_mapping);\n\n\tmy $index;\n\tfor($index=0;$index<$#commits;$index++) {\n\t\t$current_commit=$commits[$index];\n\t\t$current_revision=\"\";\n\t\tif($orig_line_count==0 || $children_count{$current_commit}==0) {\n\t\t\tmark_all(1);\n\t\t\tshow_current();\n\t\t\treturn;\n\t\t} else {\n\t\t\t$next_commit=$commits[$index+1];\n\t\t\tif($parent_tree{$next_commit} ne $current_commit) {\n\t\t\t\t# current_commit has children, so save the line mapping\n\t\t\t\tmy @new_mapping=@mapping; # force copy\n\t\t\t\t$commit_mappings{$current_commit}=\\@new_mapping;\n\n\t\t\t\t# get current_commit (which is the parent of next_commit)\n\t\t\t\t$current_commit=$parent_tree{$next_commit};\n\t\t\t\tif($commit_mappings{$current_commit}==undef) {\n\t\t\t\t\tdie \"fatal\";\n\t\t\t\t}\n\t\t\t\t@mapping=@{$commit_mappings{$current_commit}};\n\n\t\t\t\t# free memory\n\t\t\t\tif($children_count{$current_commit}==1) {\n\t\t\t\t\t$commit_mappings{$current_commit}=undef; \n\t\t\t\t}\n\t\t\t}\n\t\t\thandle_diff(\"git-diff-tree -p $next_commit $current_commit $file|\",$children_count{$current_commit}==1);\n\t\t\t# if there are multiple children, save the line mapping\n\t\t\tif($children_count{$next_commit}>1) {\n\t\t\t\tmy @new_mapping=@mapping; # force copy\n\t\t\t\t$commit_mappings{$next_commit}=\\@new_mapping;\n\t\t\t}\n\t\t}\n\t}\n\tshow_current();\n}\n\nsub parse_revision_format($) {\n\tmy $format=$_[0];\n\t$revision_string_length=0;\n\t@revision_format=();\n\tforeach $f (split(\",\",$format)) {\n\t\tif($f=~/^(.*):(.*)/) {\n\t\t\tpush @revision_format,($1,$2);\n\t\t} else {\n\t\t\tpush @revision_format,($f,16);\n\t\t}\n\t\t$revision_string_length+=$revision_format[$#revision_format]+1;\n\t}\n\tif($#revision_format<1) {\n\t\tpush @revision_format,(\"commit\",40);\n\t\t$revision_string_length=$revision_format[$#revision_format]+1;\n\t}\n}\n\nsub get_parent_tree($) {\n\tmy $head=$_[0];\n\tmy $i;\n\n\t%parent_tree=();\n\t%children_count=();\n\t@commits=();\n\t$next_commit=\"\";\n\n\topen REVS, \"git-rev-list --parents \".($head eq \"\"?\"HEAD\":$head).\"|\";\n\tLOOP: while(<REVS>) {\n\t\tif($first_parent_only && $next_commit ne \"\") {\n\t\t\twhile(!/^$next_commit/) {\n\t\t\t\tif(!($_=<REVS>)) {\n\t\t\t\t\tlast LOOP;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tmy @list=split /[ \\n]/;\n\t\tpush @commits, $list[0];\n\t\tfor($i=1;$i<=$#list;$i++) {\n\t\t\t$parent_tree{$list[$i]}=$list[0];\n\t\t}\n\t\t$children_count{$list[0]}=$#list;\n\t\tif($first_parent_only) {\n\t\t\t$next_commit=$list[1];\n\t\t}\n\t}\n\tclose REVS;\n}\n\nget_parent_tree($opt_c);\nparse_revision_format($opt_f);\n\nif($#ARGV<0) {\n\topen FILES, 'git-ls-tree -r '.($opt_c eq ''?'HEAD':$opt_c).'|';\n\twhile(<FILES>) {\n\t\tif(/^\\S+\\s+\\S+\\s+\\S+\\s+(.*)$/) {\n\t\t\tpush @ARGV, $1;\n\t\t}\n\t}\n\tclose FILES;\n}\n\nfor($i=0;$i<=$#ARGV;$i++) {\n\tif($#ARGV>1) {\n\t\tprint \"File: \".$ARGV[$i].\"\\n\";\n\t}\n\tannotate_file($ARGV[$i],$opt_c);\n}\n\n"},{"id":"6781","messageId":"7vek9a8uy9.fsf_-_@assigned-by-dhcp.cox.net","threadId":"1399","inReplyTo":"Pine.LNX.4.58.0508031102590.3258@g5.osdl.org","subject":"[PATCH] (preview) Renaming push.","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2005-08-03T23:25:02Z","receivedAt":"2005-08-03T23:25:02Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Linus Torvalds <torvalds@osdl.org> writes:\n\n> The real problem with git-send-pack is that the local and remote names \n> have to be the same, which is a bug, really. It _should_ be perfectly fine \n> to do something like\n>\n> \tgit-send-pack ..dest.. localname:remotename\n>\n> which would push the local \"localname\" branch to the remote \"remotename\" \n> branch.\n\nYes, and that is what I have been cooking today ;-).\n\nThis patch is a preview, only because I have not converted the\npull side yet.  My limited testing shows that you can push refs\nunder different names fine with this patch.\n\nThe plan is to also let people say the renaming for pull side\nlike this.\n\n        git-fetch-pack <remote> remotename:localname...\n\nNote that remote/local is confusing when we consider both pull\nand push sides, so we should call them srcname and dstname.  The\ncommit message uses these words.\n\n-jc\n\n------------\nThis allows git-send-pack to push local refs to a destination\nrepository under different names.\n\nHere is the name mapping rules for refs.\n\n* If there is no ref mapping on the command line:\n\n - if '--all' is specified, it is equivalent to specifying\n   <local> \":\" <local> for all the existing local refs on the\n   command line\n - otherwise, it is equivalent to specifying <ref> \":\" <ref> for\n   all the refs that exist on both sides.\n\n* <name> is just a shorthand for <name> \":\" <name>\n\n* <src> \":\" <dst>\n\n  push ref that matches <src> to ref that matches <dst>.\n\n  - It is an error if <src> does not match exactly one of local\n    refs.\n\n  - It is an error if <dst> matches more than one remote refs.\n\n  - If <dst> does not match any remote refs, either\n\n    - it has to start with \"refs/\"; <dst> is used as the\n      destination literally in this case.\n\n    - <src> == <dst> and the ref that matched the <src> must not\n      exist in the set of remote refs; the ref matched <src>\n      locally is used as the name of the destination.\n\nFor example,\n\n  - \"git-send-pack --all <remote>\" works exactly as before;\n\n  - \"git-send-pack <remote> master:upstream\" pushes local master\n    to remote ref that matches \"upstream\".  If there is no such\n    ref, it is an error.\n\n  - \"git-send-pack <remote> master:refs/heads/upstream\" pushes\n    local master to remote refs/heads/upstream, even when\n    refs/heads/upstream does not exist.\n\n  - \"git-send-pack <remote> master\" into an empty remote\n    repository pushes the local ref/heads/master to the remote\n    ref/heads/master.\n\nSigned-off-by: Junio C Hamano <junkio@cox.net>\n---\n\n cache.h     |    3 +\n connect.c   |  172 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-\n send-pack.c |  146 ++++++++++++++++++++------------------------------\n 3 files changed, 230 insertions(+), 91 deletions(-)\n\nb959d297c7206b0b634160ac015122f70389415b\ndiff --git a/cache.h b/cache.h\n--- a/cache.h\n+++ b/cache.h\n@@ -298,12 +298,15 @@ struct ref {\n \tstruct ref *next;\n \tunsigned char old_sha1[20];\n \tunsigned char new_sha1[20];\n+\tstruct ref *peer_ref; /* when renaming */\n \tchar name[0];\n };\n \n extern int git_connect(int fd[2], char *url, const char *prog);\n extern int finish_connect(pid_t pid);\n extern int path_match(const char *path, int nr, char **match);\n+extern int match_refs(struct ref *src, struct ref *dst, struct ref ***dst_tail,\n+\t\t      int nr_refspec, char **refspec, int all);\n extern int get_ack(int fd, unsigned char *result_sha1);\n extern struct ref **get_remote_heads(int in, struct ref **list, int nr_match, char **match);\n \ndiff --git a/connect.c b/connect.c\n--- a/connect.c\n+++ b/connect.c\n@@ -31,11 +31,9 @@ struct ref **get_remote_heads(int in, st\n \t\tname = buffer + 41;\n \t\tif (nr_match && !path_match(name, nr_match, match))\n \t\t\tcontinue;\n-\t\tref = xmalloc(sizeof(*ref) + len - 40);\n+\t\tref = xcalloc(1, sizeof(*ref) + len - 40);\n \t\tmemcpy(ref->old_sha1, old_sha1, 20);\n-\t\tmemset(ref->new_sha1, 0, 20);\n \t\tmemcpy(ref->name, buffer + 41, len - 40);\n-\t\tref->next = NULL;\n \t\t*list = ref;\n \t\tlist = &ref->next;\n \t}\n@@ -81,6 +79,174 @@ int path_match(const char *path, int nr,\n \treturn 0;\n }\n \n+struct refspec {\n+\tchar *src;\n+\tchar *dst;\n+};\n+\n+static struct refspec *parse_ref_spec(int nr_refspec, char **refspec)\n+{\n+\tint i;\n+\tstruct refspec *rs = xmalloc(sizeof(*rs) * (nr_refspec + 1));\n+\tfor (i = 0; i < nr_refspec; i++) {\n+\t\tchar *sp, *dp, *ep;\n+\t\tsp = refspec[i];\n+\t\tep = strchr(sp, ':');\n+\t\tif (ep) {\n+\t\t\tdp = ep + 1;\n+\t\t\t*ep = 0;\n+\t\t}\n+\t\telse\n+\t\t\tdp = sp;\n+\t\trs[i].src = sp;\n+\t\trs[i].dst = dp;\n+\t}\n+\trs[nr_refspec].src = rs[nr_refspec].dst = NULL;\n+\treturn rs;\n+}\n+\n+static int count_refspec_match(const char *pattern,\n+\t\t\t       struct ref *refs,\n+\t\t\t       struct ref **matched_ref)\n+{\n+\tint match;\n+\tint patlen = strlen(pattern);\n+\n+\tfor (match = 0; refs; refs = refs->next) {\n+\t\tchar *name = refs->name;\n+\t\tint namelen = strlen(name);\n+\t\tif (namelen < patlen ||\n+\t\t    memcmp(name + namelen - patlen, pattern, patlen))\n+\t\t\tcontinue;\n+\t\tif (namelen != patlen && name[namelen - patlen - 1] != '/')\n+\t\t\tcontinue;\n+\t\tmatch++;\n+\t\t*matched_ref = refs;\n+\t}\n+\treturn match;\n+}\n+\n+static void link_dst_tail(struct ref *ref, struct ref ***tail)\n+{\n+\t**tail = ref;\n+\t*tail = &ref->next;\n+\t**tail = NULL;\n+}\n+\n+static int match_explicit_refs(struct ref *src, struct ref *dst,\n+\t\t\t       struct ref ***dst_tail, struct refspec *rs)\n+{\n+\tint i, errs;\n+\tfor (i = errs = 0; rs[i].src; i++) {\n+\t\tstruct ref *matched_src, *matched_dst;\n+\n+\t\tmatched_src = matched_dst = NULL;\n+\t\tswitch (count_refspec_match(rs[i].src, src, &matched_src)) {\n+\t\tcase 1:\n+\t\t\tbreak;\n+\t\tcase 0:\n+\t\t\terrs = 1;\n+\t\t\terror(\"src refspec %s does not match any.\");\n+\t\t\tbreak;\n+\t\tdefault:\n+\t\t\terrs = 1;\n+\t\t\terror(\"src refspec %s matches more than one.\",\n+\t\t\t      rs[i].src);\n+\t\t\tbreak;\n+\t\t}\n+\t\tswitch (count_refspec_match(rs[i].dst, dst, &matched_dst)) {\n+\t\tcase 1:\n+\t\t\tbreak;\n+\t\tcase 0:\n+\t\t\tif (!memcmp(rs[i].dst, \"refs/\", 5)) {\n+\t\t\t\tint len = strlen(rs[i].dst) + 1;\n+\t\t\t\tmatched_dst = xcalloc(1, sizeof(*dst) + len);\n+\t\t\t\tmemcpy(matched_dst->name, rs[i].dst, len);\n+\t\t\t\tlink_dst_tail(matched_dst, dst_tail);\n+\t\t\t}\n+\t\t\telse if (!strcmp(rs[i].src, rs[i].dst) &&\n+\t\t\t\t matched_src) {\n+\t\t\t\t/* pushing \"master:master\" when\n+\t\t\t\t * remote does not have master yet.\n+\t\t\t\t */\n+\t\t\t\tint len = strlen(matched_src->name);\n+\t\t\t\tmatched_dst = xcalloc(1, sizeof(*dst) + len);\n+\t\t\t\tmemcpy(matched_dst->name, matched_src->name,\n+\t\t\t\t       len);\n+\t\t\t\tlink_dst_tail(matched_dst, dst_tail);\n+\t\t\t}\n+\t\t\telse {\n+\t\t\t\terrs = 1;\n+\t\t\t\terror(\"dst refspec %s does not match any \"\n+\t\t\t\t      \"existing ref on the remote and does \"\n+\t\t\t\t      \"not start with refs/.\", rs[i].dst);\n+\t\t\t}\n+\t\t\tbreak;\n+\t\tdefault:\n+\t\t\terrs = 1;\n+\t\t\terror(\"dst refspec %s matches more than one.\",\n+\t\t\t      rs[i].dst);\n+\t\t\tbreak;\n+\t\t}\n+\t\tif (errs)\n+\t\t\tcontinue;\n+\t\tif (matched_src->peer_ref) {\n+\t\t\terrs = 1;\n+\t\t\terror(\"src ref %s is sent to more than one dst.\",\n+\t\t\t      matched_src->name);\n+\t\t}\n+\t\telse\n+\t\t\tmatched_src->peer_ref = matched_dst;\n+\t\tif (matched_dst->peer_ref) {\n+\t\t\terrs = 1;\n+\t\t\terror(\"dst ref %s receives from more than one src.\",\n+\t\t\t      matched_dst->name);\n+\t\t}\n+\t\telse\n+\t\t\tmatched_dst->peer_ref = matched_src;\n+\t}\n+\treturn -errs;\n+}\n+\n+static struct ref *find_ref_by_name(struct ref *list, const char *name)\n+{\n+\tfor ( ; list; list = list->next)\n+\t\tif (!strcmp(list->name, name))\n+\t\t\treturn list;\n+\treturn NULL;\n+}\n+\n+int match_refs(struct ref *src, struct ref *dst, struct ref ***dst_tail,\n+\t       int nr_refspec, char **refspec, int all)\n+{\n+\tstruct refspec *rs = parse_ref_spec(nr_refspec, refspec);\n+\n+\tif (nr_refspec)\n+\t\treturn match_explicit_refs(src, dst, dst_tail, rs);\n+\n+\t/* pick the remainder */\n+\tfor ( ; src; src = src->next) {\n+\t\tstruct ref *dst_peer;\n+\t\tif (src->peer_ref)\n+\t\t\tcontinue;\n+\t\tdst_peer = find_ref_by_name(dst, src->name);\n+\t\tif (dst_peer && dst_peer->peer_ref)\n+\t\t\tcontinue;\n+\t\tif (!dst_peer) {\n+\t\t\tif (!all)\n+\t\t\t\tcontinue;\n+\t\t\t/* Create a new one and link it */\n+\t\t\tint len = strlen(src->name) + 1;\n+\t\t\tdst_peer = xcalloc(1, sizeof(*dst_peer) + len);\n+\t\t\tmemcpy(dst_peer->name, src->name, len);\n+\t\t\tmemcpy(dst_peer->new_sha1, src->new_sha1, 20);\n+\t\t\tlink_dst_tail(dst_peer, dst_tail);\n+\t\t}\n+\t\tdst_peer->peer_ref = src;\n+\t}\n+\treturn 0;\n+}\n+\n enum protocol {\n \tPROTO_LOCAL = 1,\n \tPROTO_SSH,\ndiff --git a/send-pack.c b/send-pack.c\n--- a/send-pack.c\n+++ b/send-pack.c\n@@ -43,7 +43,8 @@ static void exec_rev_list(struct ref *re\n \t\tchar *buf = malloc(100);\n \t\tif (i > 900)\n \t\t\tdie(\"git-rev-list environment overflow\");\n-\t\tif (!is_zero_sha1(refs->old_sha1)) {\n+\t\tif (!is_zero_sha1(refs->old_sha1) &&\n+\t\t    has_sha1_file(refs->old_sha1)) {\n \t\t\targs[i++] = buf;\n \t\t\tsnprintf(buf, 50, \"^%s\", sha1_to_hex(refs->old_sha1));\n \t\t\tbuf += 50;\n@@ -103,21 +104,6 @@ static int pack_objects(int fd, struct r\n \treturn 0;\n }\n \n-static int read_ref(const char *ref, unsigned char *sha1)\n-{\n-\tint fd, ret;\n-\tchar buffer[60];\n-\n-\tfd = open(git_path(\"%s\", ref), O_RDONLY);\n-\tif (fd < 0)\n-\t\treturn -1;\n-\tret = -1;\n-\tif (read(fd, buffer, sizeof(buffer)) >= 40)\n-\t\tret = get_sha1_hex(buffer, sha1);\n-\tclose(fd);\n-\treturn ret;\n-}\n-\n static int ref_newer(const unsigned char *new_sha1, const unsigned char *old_sha1)\n {\n \tstruct commit *new, *old;\n@@ -143,108 +129,92 @@ static int ref_newer(const unsigned char\n \treturn 0;\n }\n \n-static int local_ref_nr_match;\n-static char **local_ref_match;\n-static struct ref *local_ref_list;\n-static struct ref **local_last_ref;\n+static struct ref *local_refs, **local_tail;\n+static struct ref *remote_refs, **remote_tail;\n \n-static int try_to_match(const char *refname, const unsigned char *sha1)\n+static int one_local_ref(const char *refname, const unsigned char *sha1)\n {\n \tstruct ref *ref;\n-\tint len;\n-\n-\tif (!path_match(refname, local_ref_nr_match, local_ref_match)) {\n-\t\tif (!send_all)\n-\t\t\treturn 0;\n-\n-\t\t/* If we have it listed already, skip it */\n-\t\tfor (ref = local_ref_list ; ref ; ref = ref->next) {\n-\t\t\tif (!strcmp(ref->name, refname))\n-\t\t\t\treturn 0;\n-\t\t}\n-\t}\n-\n-\tlen = strlen(refname)+1;\n-\tref = xmalloc(sizeof(*ref) + len);\n-\tmemset(ref->old_sha1, 0, 20);\n+\tint len = strlen(refname) + 1;\n+\tref = xcalloc(1, sizeof(*ref) + len);\n \tmemcpy(ref->new_sha1, sha1, 20);\n \tmemcpy(ref->name, refname, len);\n-\tref->next = NULL;\n-\t*local_last_ref = ref;\n-\tlocal_last_ref = &ref->next;\n+\t*local_tail = ref;\n+\tlocal_tail = &ref->next;\n \treturn 0;\n }\n \n-static int send_pack(int in, int out, int nr_match, char **match)\n+static void get_local_heads(void)\n+{\n+\tlocal_tail = &local_refs;\n+\tfor_each_ref(one_local_ref);\n+}\n+\n+static int send_pack(int in, int out, int nr_refspec, char **refspec)\n {\n-\tstruct ref *ref_list, **last_ref;\n \tstruct ref *ref;\n \tint new_refs;\n \n-\t/* First we get all heads, whether matching or not.. */\n-\tlast_ref = get_remote_heads(in, &ref_list, 0, NULL);\n-\n+\t/* No funny business with the matcher */\n+\tremote_tail = get_remote_heads(in, &remote_refs, 0, NULL);\n+\tget_local_heads();\n+\n+\t/* match them up */\n+\tif (!remote_tail)\n+\t\tremote_tail = &remote_refs;\n+\tif (match_refs(local_refs, remote_refs, &remote_tail,\n+\t\t       nr_refspec, refspec, send_all))\n+\t\treturn -1;\n \t/*\n-\t * Go through the refs, see if we want to update\n-\t * any of them..\n+\t * Finally, tell the other end!\n \t */\n-\tfor (ref = ref_list; ref; ref = ref->next) {\n-\t\tunsigned char new_sha1[20];\n-\t\tchar *name = ref->name;\n-\n-\t\tif (nr_match && !path_match(name, nr_match, match))\n-\t\t\tcontinue;\n-\n-\t\tif (read_ref(name, new_sha1) < 0)\n-\t\t\tcontinue;\n-\n-\t\tif (!memcmp(ref->old_sha1, new_sha1, 20)) {\n-\t\t\tfprintf(stderr, \"'%s' unchanged\\n\", name);\n+\tnew_refs = 0;\n+\tfor (ref = remote_refs; ref; ref = ref->next) {\n+\t\tchar old_hex[60], *new_hex;\n+\t\tif (!ref->peer_ref)\n \t\t\tcontinue;\n+\t\tif (!is_zero_sha1(ref->old_sha1)) {\n+\t\t\tif (!has_sha1_file(ref->old_sha1)) {\n+\t\t\t\terror(\"remote '%s' object %s does not \"\n+\t\t\t\t      \"exist on local\",\n+\t\t\t\t      ref->name, sha1_to_hex(ref->old_sha1));\n+\t\t\t\tcontinue;\n+\t\t\t}\n+\t\t\tif (!ref_newer(ref->peer_ref->new_sha1,\n+\t\t\t\t       ref->old_sha1)) {\n+\t\t\t\terror(\"remote ref '%s' is not a strict \"\n+\t\t\t\t      \"subset of local ref '%s'.\", ref->name,\n+\t\t\t\t      ref->peer_ref->name);\n+\t\t\t\tcontinue;\n+\t\t\t}\n \t\t}\n-\n-\t\tif (!ref_newer(new_sha1, ref->old_sha1)) {\n-\t\t\terror(\"remote '%s' isn't a strict parent of local\", name);\n+\t\tif (!memcmp(ref->old_sha1, ref->peer_ref->new_sha1, 20)) {\n+\t\t\tfprintf(stderr, \"'%s': up-to-date\\n\", ref->name);\n \t\t\tcontinue;\n \t\t}\n-\n-\t\t/* Ok, mark it for update */\n-\t\tmemcpy(ref->new_sha1, new_sha1, 20);\n-\t}\n-\n-\t/*\n-\t * See if we have any refs that the other end didn't have\n-\t */\n-\tif (nr_match || send_all) {\n-\t\tlocal_ref_nr_match = nr_match;\n-\t\tlocal_ref_match = match;\n-\t\tlocal_ref_list = ref_list;\n-\t\tlocal_last_ref = last_ref;\n-\t\tfor_each_ref(try_to_match);\n-\t}\n-\n-\t/*\n-\t * Finally, tell the other end!\n-\t */\n-\tnew_refs = 0;\n-\tfor (ref = ref_list; ref; ref = ref->next) {\n-\t\tchar old_hex[60], *new_hex;\n-\t\tif (is_zero_sha1(ref->new_sha1))\n+\t\tmemcpy(ref->new_sha1, ref->peer_ref->new_sha1, 20);\n+\t\tif (is_zero_sha1(ref->new_sha1)) {\n+\t\t\terror(\"cannot happen anymore\");\n \t\t\tcontinue;\n+\t\t}\n \t\tnew_refs++;\n \t\tstrcpy(old_hex, sha1_to_hex(ref->old_sha1));\n \t\tnew_hex = sha1_to_hex(ref->new_sha1);\n \t\tpacket_write(out, \"%s %s %s\", old_hex, new_hex, ref->name);\n-\t\tfprintf(stderr, \"'%s': updating from %s to %s\\n\", ref->name, old_hex, new_hex);\n+\t\tfprintf(stderr, \"updating '%s'\", ref->name);\n+\t\tif (strcmp(ref->name, ref->peer_ref->name))\n+\t\t\tfprintf(stderr, \" using '%s'\", ref->peer_ref->name);\n+\t\tfprintf(stderr, \"\\n  from %s\\n  to   %s\\n\", old_hex, new_hex);\n \t}\n-\t\n+\n \tpacket_flush(out);\n \tif (new_refs)\n-\t\tpack_objects(out, ref_list);\n+\t\tpack_objects(out, remote_refs);\n \tclose(out);\n \treturn 0;\n }\n \n+\n int main(int argc, char **argv)\n {\n \tint i, nr_heads = 0;\n"},{"id":"6783","messageId":"Pine.LNX.4.58.0508031641270.3258@g5.osdl.org","threadId":"1399","inReplyTo":"7vek9a8uy9.fsf_-_@assigned-by-dhcp.cox.net","subject":"Re: [PATCH] (preview) Renaming push.","fromName":"Linus Torvalds","fromEmail":"torvalds@osdl.org","sentAt":"2005-08-03T23:48:13Z","receivedAt":"2005-08-03T23:48:13Z","isPatch":true,"sender":{"key":"torvalds@linux-foundation.org","avatar":"https://avatars.githubusercontent.com/u/1024025?v=4"},"body":"\n\nOn Wed, 3 Aug 2005, Junio C Hamano wrote:\n>\n> This allows git-send-pack to push local refs to a destination\n> repository under different names.\n\nLooks good, except I was almost hoping for one modification:\n\n> Here is the name mapping rules for refs.\n> \n> * If there is no ref mapping on the command line:\n> \n>  - if '--all' is specified, it is equivalent to specifying\n>    <local> \":\" <local> for all the existing local refs on the\n>    command line\n>  - otherwise, it is equivalent to specifying <ref> \":\" <ref> for\n>    all the refs that exist on both sides.\n> \n> * <name> is just a shorthand for <name> \":\" <name>\n> \n> * <src> \":\" <dst>\n> \n>   push ref that matches <src> to ref that matches <dst>.\n\nIn this format, \"src\" makes sense as a generic sha1_name, and _not_ \nnecessarily limited to a ref-name.\n\nIOW, there's really no reason to not allow\n\n\tgit-send-pack .. dest .. <sha1>:dst-ref\n\nwhere \"<sha1>\" may be something else than a ref (but a ref obviously ends \nup being one such thing).\n\nFor example, let's say that I've got stuff at the HEAD of my tree that I'm\nnot quite ready to push out yet, but I _do_ want to push out the parent of\nthe current head. I'd love to be able to just do\n\n\tgit-send-pack parent $(git-rev-parse HEAD^):master\n\nand there's no real reason why that syntax shouldn't just work: it's \nentirely logical to say \"I want to push out the parent of my HEAD as \n'master' on the other end\", and that's _exactly_ what the above says.\n\nSo:\n\n>   - It is an error if <src> does not match exactly one of local\n>     refs.\n\nI think \"src\" should just be seen as any random SHA1 name, and we should \nuse \"get_sha()\" to convert it to a SHA1.\n\nIn contrast, \"dst\" is obviously a real ref name, and as such:\n\n>   - It is an error if <dst> matches more than one remote refs.\n\nmakes sense.\n\nThat makes your next rule a bit iffy, though:\n\n>   - If <dst> does not match any remote refs, either\n> \n>     - it has to start with \"refs/\"; <dst> is used as the\n>       destination literally in this case.\n> \n>     - <src> == <dst> and the ref that matched the <src> must not\n>       exist in the set of remote refs; the ref matched <src>\n>       locally is used as the name of the destination.\n\nsince \"src\" from a local standpoint isn't really a ref-name at all.\n\nBut hey, your current patch looks fine already. It doesn't _quite_ do what \nI had in mind, but it gets very very close.\n\n\t\tLinus\n"},{"id":"6784","messageId":"7v3bpq8t2a.fsf@assigned-by-dhcp.cox.net","threadId":"1399","inReplyTo":"Pine.LNX.4.58.0508031641270.3258@g5.osdl.org","subject":"Re: [PATCH] (preview) Renaming push.","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2005-08-04T00:05:49Z","receivedAt":"2005-08-04T00:05:49Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Linus Torvalds <torvalds@osdl.org> writes:\n\n> \tgit-send-pack parent $(git-rev-parse HEAD^):master\n>\n> and there's no real reason why that syntax shouldn't just work: it's \n> entirely logical to say \"I want to push out the parent of my HEAD as \n> 'master' on the other end\", and that's _exactly_ what the above says.\n\nYes I think allowing get_sha()-able thing on the left hand side\nmakes things, well, interesting.  I need to think about it a bit.\n\nWhen I do something like your example, I create a temporary\nlightweight tag and push it.  Snapshots in JIT are just a bunch\nof lightweight tags so..\n"},{"id":"6785","messageId":"Pine.LNX.4.58.0508031710310.3258@g5.osdl.org","threadId":"1399","inReplyTo":"7v3bpq8t2a.fsf@assigned-by-dhcp.cox.net","subject":"Re: [PATCH] (preview) Renaming push.","fromName":"Linus Torvalds","fromEmail":"torvalds@osdl.org","sentAt":"2005-08-04T00:13:05Z","receivedAt":"2005-08-04T00:13:05Z","isPatch":true,"sender":{"key":"torvalds@linux-foundation.org","avatar":"https://avatars.githubusercontent.com/u/1024025?v=4"},"body":"\n\nOn Wed, 3 Aug 2005, Junio C Hamano wrote:\n>\n> > \tgit-send-pack parent $(git-rev-parse HEAD^):master\n> \n> When I do something like your example, I create a temporary\n> lightweight tag and push it.  Snapshots in JIT are just a bunch\n> of lightweight tags so..\n\nI like the scripting, and combining pipelines of commands kind of thing. \n\nI agree that you can just make a temporary tag, but it's a bit like in any\nscripting stuff - you could use a temp-file, but it's just cleaner if you\ncan keep temporary values in local variables (or in a local cmd pipeline\nlike the above).\n\nWhenever you script somethign that creates a new tag or ref, you suddenly \nhave cleanup and uniqueness issues etc. \n\n\t\tLinus\n"},{"id":"6786","messageId":"7vmzny5xac.fsf@assigned-by-dhcp.cox.net","threadId":"1399","inReplyTo":"Pine.LNX.4.58.0508031641270.3258@g5.osdl.org","subject":"Re: [PATCH] (preview) Renaming push.","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2005-08-04T01:02:51Z","receivedAt":"2005-08-04T01:02:51Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Well, I pushed it out, although I do agree that we should be\nable to give anything get_sha()-able on the source side of the\npush.  Probably a revised version should have the following\nsemantics:\n\n    $ git-send-pack [--all] <remote> [<ref>...]\n\n - When no <ref> is specified:\n\n   - with '--all', it is the same as specifying the full refs/*\n     path for all local refs;\n\n   - without '--all', it is the same as specifying the full\n     refs/* path for refs that exist on both ends;\n\n - When one or more <ref>s are specified:\n\n   - a single token <ref> (i.e. no colon) must be a pattern that\n     tail-matches refs/* path for an existing local ref.  It is\n     an error for the pattern to match no local ref, or more\n     than one local refs.  The matching ref is pushed to the\n     remote end under the same name.\n\n   - <src>:<dst> can have different cases.  <src> is first tried\n     as the tail-matching pattern for refs/* path.\n\n     - If more than one matches are found, it is an error.\n\n     - If one match is found, <dst> must either match no remote\n       ref and start with \"refs/\", or match exactly one remote\n       ref.  That remote ref is updated with the sha1 value\n       obtained by the <src> sha1.\n\n     - If no match is found, it is given to get_extended_sha1();\n       it is an error if get_extended_sha1() does not find an\n       object name.  If it succeeds, <dst> must either match\n       no remote ref and start with \"refs/\" or match exactly\n       one remote ref.  That remote ref is updated with the sha1\n       value.\n"},{"id":"6790","messageId":"7vy87i46il.fsf@assigned-by-dhcp.cox.net","threadId":"1399","inReplyTo":"Pine.LNX.4.58.0508031641270.3258@g5.osdl.org","subject":"Re: [PATCH] (preview) Renaming push.","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2005-08-04T05:26:26Z","receivedAt":"2005-08-04T05:26:26Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Linus Torvalds <torvalds@osdl.org> writes:\n\n> In this format, \"src\" makes sense as a generic sha1_name, and _not_ \n> necessarily limited to a ref-name.\n>\n> IOW, there's really no reason to not allow\n>\n> \tgit-send-pack .. dest .. <sha1>:dst-ref\n>\n> where \"<sha1>\" may be something else than a ref (but a ref obviously ends \n> up being one such thing).\n>\n> For example, let's say that I've got stuff at the HEAD of my tree that I'm\n> not quite ready to push out yet, but I _do_ want to push out the parent of\n> the current head. I'd love to be able to just do\n>\n> \tgit-send-pack parent $(git-rev-parse HEAD^):master\n>\n> and there's no real reason why that syntax shouldn't just work: it's \n> entirely logical to say \"I want to push out the parent of my HEAD as \n> 'master' on the other end\", and that's _exactly_ what the above says.\n\nWhile I have not updated the send-pack <src>:<dst> syntax, I\nadded a horrible hack that some people may love to see.  This\nremoves the need to use git-rev-parse from many commands.\n\nThis is a preview.  I've run the standard test suite and it does\nnot seem to break anything, but I expect it will stay in \"pu\"\nfor a while.\n\n------------\n[PATCH] Update get_sha1() to grok extended format.\n\nEverybody envies rev-parse, who is the only one that can grok\nthe extended sha1 format.  Move the get_extended_sha1() out of\nrev-parse, rename it to get_sha1() and make it available to\neverybody else.\n\nSigned-off-by: Junio C Hamano <junkio@cox.net>\n---\n\n Makefile    |    3 +\n rev-parse.c |  188 +-------------------------------------------------\n sha1_file.c |   39 ----------\n sha1_name.c |  222 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n 4 files changed, 229 insertions(+), 223 deletions(-)\n create mode 100644 sha1_name.c\n\n99ef7de3e234347d2af1ab2129ce99c5876b591b\ndiff --git a/Makefile b/Makefile\n--- a/Makefile\n+++ b/Makefile\n@@ -95,7 +95,8 @@ LIB_H=cache.h object.h blob.h tree.h com\n \tpack.h pkt-line.h refs.h\n LIB_OBJS=read-cache.o sha1_file.o usage.o object.o commit.o tree.o blob.o \\\n \t tag.o date.o index.o diff-delta.o patch-delta.o entry.o path.o \\\n-\t refs.o csum-file.o pack-check.o pkt-line.o connect.o ident.o\n+\t refs.o csum-file.o pack-check.o pkt-line.o connect.o ident.o \\\n+\t sha1_name.o\n \n LIB_H += rev-cache.h\n LIB_OBJS += rev-cache.o\ndiff --git a/rev-parse.c b/rev-parse.c\n--- a/rev-parse.c\n+++ b/rev-parse.c\n@@ -21,8 +21,6 @@ static int output_sq = 0;\n #define REVERSED 1\n static int show_type = NORMAL;\n \n-static int get_extended_sha1(char *name, unsigned char *sha1);\n-\n /*\n  * Some arguments are relevant \"revision\" arguments,\n  * others are about output format or other details.\n@@ -107,182 +105,6 @@ static void show_arg(char *arg)\n \t\tshow_norev(arg);\n }\n \n-static int get_parent(char *name, unsigned char *result, int idx)\n-{\n-\tunsigned char sha1[20];\n-\tint ret = get_extended_sha1(name, sha1);\n-\tstruct commit *commit;\n-\tstruct commit_list *p;\n-\n-\tif (ret)\n-\t\treturn ret;\n-\tcommit = lookup_commit_reference(sha1);\n-\tif (!commit)\n-\t\treturn -1;\n-\tif (parse_commit(commit))\n-\t\treturn -1;\n-\tif (!idx) {\n-\t\tmemcpy(result, commit->object.sha1, 20);\n-\t\treturn 0;\n-\t}\n-\tp = commit->parents;\n-\twhile (p) {\n-\t\tif (!--idx) {\n-\t\t\tmemcpy(result, p->item->object.sha1, 20);\n-\t\t\treturn 0;\n-\t\t}\n-\t\tp = p->next;\n-\t}\n-\treturn -1;\n-}\n-\n-static int find_short_object_filename(int len, const char *name, unsigned char *sha1)\n-{\n-\tstatic char dirname[PATH_MAX];\n-\tchar hex[40];\n-\tDIR *dir;\n-\tint found;\n-\n-\tsnprintf(dirname, sizeof(dirname), \"%s/%.2s\", get_object_directory(), name);\n-\tdir = opendir(dirname);\n-\tsprintf(hex, \"%.2s\", name);\n-\tfound = 0;\n-\tif (dir) {\n-\t\tstruct dirent *de;\n-\t\twhile ((de = readdir(dir)) != NULL) {\n-\t\t\tif (strlen(de->d_name) != 38)\n-\t\t\t\tcontinue;\n-\t\t\tif (memcmp(de->d_name, name + 2, len-2))\n-\t\t\t\tcontinue;\n-\t\t\tmemcpy(hex + 2, de->d_name, 38);\n-\t\t\tif (++found > 1)\n-\t\t\t\tbreak;\n-\t\t}\n-\t\tclosedir(dir);\n-\t}\n-\tif (found == 1)\n-\t\treturn get_sha1_hex(hex, sha1) == 0;\n-\treturn 0;\n-}\n-\n-static int match_sha(unsigned len, const unsigned char *a, const unsigned char *b)\n-{\n-\tdo {\n-\t\tif (*a != *b)\n-\t\t\treturn 0;\n-\t\ta++;\n-\t\tb++;\n-\t\tlen -= 2;\n-\t} while (len > 1);\n-\tif (len)\n-\t\tif ((*a ^ *b) & 0xf0)\n-\t\t\treturn 0;\n-\treturn 1;\n-}\n-\n-static int find_short_packed_object(int len, const unsigned char *match, unsigned char *sha1)\n-{\n-\tstruct packed_git *p;\n-\n-\tprepare_packed_git();\n-\tfor (p = packed_git; p; p = p->next) {\n-\t\tunsigned num = num_packed_objects(p);\n-\t\tunsigned first = 0, last = num;\n-\t\twhile (first < last) {\n-\t\t\tunsigned mid = (first + last) / 2;\n-\t\t\tunsigned char now[20];\n-\t\t\tint cmp;\n-\n-\t\t\tnth_packed_object_sha1(p, mid, now);\n-\t\t\tcmp = memcmp(match, now, 20);\n-\t\t\tif (!cmp) {\n-\t\t\t\tfirst = mid;\n-\t\t\t\tbreak;\n-\t\t\t}\n-\t\t\tif (cmp > 0) {\n-\t\t\t\tfirst = mid+1;\n-\t\t\t\tcontinue;\n-\t\t\t}\n-\t\t\tlast = mid;\n-\t\t}\n-\t\tif (first < num) {\n-\t\t\tunsigned char now[20], next[20];\n-\t\t\tnth_packed_object_sha1(p, first, now);\n-\t\t\tif (match_sha(len, match, now)) {\n-\t\t\t\tif (nth_packed_object_sha1(p, first+1, next) || !match_sha(len, match, next)) {\n-\t\t\t\t\tmemcpy(sha1, now, 20);\n-\t\t\t\t\treturn 1;\n-\t\t\t\t}\n-\t\t\t}\n-\t\t}\t\n-\t}\n-\treturn 0;\n-}\n-\n-static int get_short_sha1(char *name, unsigned char *sha1)\n-{\n-\tint i;\n-\tchar canonical[40];\n-\tunsigned char res[20];\n-\n-\tmemset(res, 0, 20);\n-\tmemset(canonical, 'x', 40);\n-\tfor (i = 0;;i++) {\n-\t\tunsigned char c = name[i];\n-\t\tunsigned char val;\n-\t\tif (!c || i > 40)\n-\t\t\tbreak;\n-\t\tif (c >= '0' && c <= '9')\n-\t\t\tval = c - '0';\n-\t\telse if (c >= 'a' && c <= 'f')\n-\t\t\tval = c - 'a' + 10;\n-\t\telse if (c >= 'A' && c <='F') {\n-\t\t\tval = c - 'A' + 10;\n-\t\t\tc -= 'A' - 'a';\n-\t\t}\n-\t\telse\n-\t\t\treturn -1;\n-\t\tcanonical[i] = c;\n-\t\tif (!(i & 1))\n-\t\t\tval <<= 4;\n-\t\tres[i >> 1] |= val;\n-\t}\n-\tif (i < 4)\n-\t\treturn -1;\n-\tif (find_short_object_filename(i, canonical, sha1))\n-\t\treturn 0;\n-\tif (find_short_packed_object(i, res, sha1))\n-\t\treturn 0;\n-\treturn -1;\n-}\n-\n-/*\n- * This is like \"get_sha1()\", except it allows \"sha1 expressions\",\n- * notably \"xyz^\" for \"parent of xyz\"\n- */\n-static int get_extended_sha1(char *name, unsigned char *sha1)\n-{\n-\tint parent, ret;\n-\tint len = strlen(name);\n-\n-\tparent = 1;\n-\tif (len > 2 && name[len-1] >= '0' && name[len-1] <= '9') {\n-\t\tparent = name[len-1] - '0';\n-\t\tlen--;\n-\t}\n-\tif (len > 1 && name[len-1] == '^') {\n-\t\tname[len-1] = 0;\n-\t\tret = get_parent(name, sha1, parent);\n-\t\tname[len-1] = '^';\n-\t\tif (!ret)\n-\t\t\treturn 0;\n-\t}\n-\tret = get_sha1(name, sha1);\n-\tif (!ret)\n-\t\treturn 0;\n-\treturn get_short_sha1(name, sha1);\n-}\n-\n static void show_default(void)\n {\n \tchar *s = def;\n@@ -291,7 +113,7 @@ static void show_default(void)\n \t\tunsigned char sha1[20];\n \n \t\tdef = NULL;\n-\t\tif (!get_extended_sha1(s, sha1)) {\n+\t\tif (!get_sha1(s, sha1)) {\n \t\t\tshow_rev(NORMAL, sha1);\n \t\t\treturn;\n \t\t}\n@@ -372,10 +194,10 @@ int main(int argc, char **argv)\n \t\t\tunsigned char end[20];\n \t\t\tchar *n = dotdot+2;\n \t\t\t*dotdot = 0;\n-\t\t\tif (!get_extended_sha1(arg, sha1)) {\n+\t\t\tif (!get_sha1(arg, sha1)) {\n \t\t\t\tif (!*n)\n \t\t\t\t\tn = \"HEAD\";\n-\t\t\t\tif (!get_extended_sha1(n, end)) {\n+\t\t\t\tif (!get_sha1(n, end)) {\n \t\t\t\t\tif (no_revs)\n \t\t\t\t\t\tcontinue;\n \t\t\t\t\tdef = NULL;\n@@ -386,14 +208,14 @@ int main(int argc, char **argv)\n \t\t\t}\n \t\t\t*dotdot = '.';\n \t\t}\n-\t\tif (!get_extended_sha1(arg, sha1)) {\n+\t\tif (!get_sha1(arg, sha1)) {\n \t\t\tif (no_revs)\n \t\t\t\tcontinue;\n \t\t\tdef = NULL;\n \t\t\tshow_rev(NORMAL, sha1);\n \t\t\tcontinue;\n \t\t}\n-\t\tif (*arg == '^' && !get_extended_sha1(arg+1, sha1)) {\n+\t\tif (*arg == '^' && !get_sha1(arg+1, sha1)) {\n \t\t\tif (no_revs)\n \t\t\t\tcontinue;\n \t\t\tdef = NULL;\ndiff --git a/sha1_file.c b/sha1_file.c\n--- a/sha1_file.c\n+++ b/sha1_file.c\n@@ -46,21 +46,6 @@ int get_sha1_hex(const char *hex, unsign\n \treturn 0;\n }\n \n-static int get_sha1_file(const char *path, unsigned char *result)\n-{\n-\tchar buffer[60];\n-\tint fd = open(path, O_RDONLY);\n-\tint len;\n-\n-\tif (fd < 0)\n-\t\treturn -1;\n-\tlen = read(fd, buffer, sizeof(buffer));\n-\tclose(fd);\n-\tif (len < 40)\n-\t\treturn -1;\n-\treturn get_sha1_hex(buffer, result);\n-}\n-\n static char *git_dir, *git_object_dir, *git_index_file, *git_refs_dir,\n \t*git_graft_file;\n static void setup_git_env(void)\n@@ -132,30 +117,6 @@ int safe_create_leading_directories(char\n \treturn 0;\n }\n \n-int get_sha1(const char *str, unsigned char *sha1)\n-{\n-\tstatic const char *prefix[] = {\n-\t\t\"\",\n-\t\t\"refs\",\n-\t\t\"refs/tags\",\n-\t\t\"refs/heads\",\n-\t\t\"refs/snap\",\n-\t\tNULL\n-\t};\n-\tconst char **p;\n-\n-\tif (!get_sha1_hex(str, sha1))\n-\t\treturn 0;\n-\n-\tfor (p = prefix; *p; p++) {\n-\t\tchar * pathname = git_path(\"%s/%s\", *p, str);\n-\t\tif (!get_sha1_file(pathname, sha1))\n-\t\t\treturn 0;\n-\t}\n-\n-\treturn -1;\n-}\n-\n char * sha1_to_hex(const unsigned char *sha1)\n {\n \tstatic char buffer[50];\ndiff --git a/sha1_name.c b/sha1_name.c\nnew file mode 100644\n--- /dev/null\n+++ b/sha1_name.c\n@@ -0,0 +1,222 @@\n+#include \"cache.h\"\n+#include \"commit.h\"\n+\n+static int find_short_object_filename(int len, const char *name, unsigned char *sha1)\n+{\n+\tstatic char dirname[PATH_MAX];\n+\tchar hex[40];\n+\tDIR *dir;\n+\tint found;\n+\n+\tsnprintf(dirname, sizeof(dirname), \"%s/%.2s\", get_object_directory(), name);\n+\tdir = opendir(dirname);\n+\tsprintf(hex, \"%.2s\", name);\n+\tfound = 0;\n+\tif (dir) {\n+\t\tstruct dirent *de;\n+\t\twhile ((de = readdir(dir)) != NULL) {\n+\t\t\tif (strlen(de->d_name) != 38)\n+\t\t\t\tcontinue;\n+\t\t\tif (memcmp(de->d_name, name + 2, len-2))\n+\t\t\t\tcontinue;\n+\t\t\tmemcpy(hex + 2, de->d_name, 38);\n+\t\t\tif (++found > 1)\n+\t\t\t\tbreak;\n+\t\t}\n+\t\tclosedir(dir);\n+\t}\n+\tif (found == 1)\n+\t\treturn get_sha1_hex(hex, sha1) == 0;\n+\treturn 0;\n+}\n+\n+static int match_sha(unsigned len, const unsigned char *a, const unsigned char *b)\n+{\n+\tdo {\n+\t\tif (*a != *b)\n+\t\t\treturn 0;\n+\t\ta++;\n+\t\tb++;\n+\t\tlen -= 2;\n+\t} while (len > 1);\n+\tif (len)\n+\t\tif ((*a ^ *b) & 0xf0)\n+\t\t\treturn 0;\n+\treturn 1;\n+}\n+\n+static int find_short_packed_object(int len, const unsigned char *match, unsigned char *sha1)\n+{\n+\tstruct packed_git *p;\n+\n+\tprepare_packed_git();\n+\tfor (p = packed_git; p; p = p->next) {\n+\t\tunsigned num = num_packed_objects(p);\n+\t\tunsigned first = 0, last = num;\n+\t\twhile (first < last) {\n+\t\t\tunsigned mid = (first + last) / 2;\n+\t\t\tunsigned char now[20];\n+\t\t\tint cmp;\n+\n+\t\t\tnth_packed_object_sha1(p, mid, now);\n+\t\t\tcmp = memcmp(match, now, 20);\n+\t\t\tif (!cmp) {\n+\t\t\t\tfirst = mid;\n+\t\t\t\tbreak;\n+\t\t\t}\n+\t\t\tif (cmp > 0) {\n+\t\t\t\tfirst = mid+1;\n+\t\t\t\tcontinue;\n+\t\t\t}\n+\t\t\tlast = mid;\n+\t\t}\n+\t\tif (first < num) {\n+\t\t\tunsigned char now[20], next[20];\n+\t\t\tnth_packed_object_sha1(p, first, now);\n+\t\t\tif (match_sha(len, match, now)) {\n+\t\t\t\tif (nth_packed_object_sha1(p, first+1, next) || !match_sha(len, match, next)) {\n+\t\t\t\t\tmemcpy(sha1, now, 20);\n+\t\t\t\t\treturn 1;\n+\t\t\t\t}\n+\t\t\t}\n+\t\t}\n+\t}\n+\treturn 0;\n+}\n+\n+static int get_short_sha1(const char *name, unsigned char *sha1)\n+{\n+\tint i;\n+\tchar canonical[40];\n+\tunsigned char res[20];\n+\n+\tmemset(res, 0, 20);\n+\tmemset(canonical, 'x', 40);\n+\tfor (i = 0;;i++) {\n+\t\tunsigned char c = name[i];\n+\t\tunsigned char val;\n+\t\tif (!c || i > 40)\n+\t\t\tbreak;\n+\t\tif (c >= '0' && c <= '9')\n+\t\t\tval = c - '0';\n+\t\telse if (c >= 'a' && c <= 'f')\n+\t\t\tval = c - 'a' + 10;\n+\t\telse if (c >= 'A' && c <='F') {\n+\t\t\tval = c - 'A' + 10;\n+\t\t\tc -= 'A' - 'a';\n+\t\t}\n+\t\telse\n+\t\t\treturn -1;\n+\t\tcanonical[i] = c;\n+\t\tif (!(i & 1))\n+\t\t\tval <<= 4;\n+\t\tres[i >> 1] |= val;\n+\t}\n+\tif (i < 4)\n+\t\treturn -1;\n+\tif (find_short_object_filename(i, canonical, sha1))\n+\t\treturn 0;\n+\tif (find_short_packed_object(i, res, sha1))\n+\t\treturn 0;\n+\treturn -1;\n+}\n+\n+static int get_sha1_file(const char *path, unsigned char *result)\n+{\n+\tchar buffer[60];\n+\tint fd = open(path, O_RDONLY);\n+\tint len;\n+\n+\tif (fd < 0)\n+\t\treturn -1;\n+\tlen = read(fd, buffer, sizeof(buffer));\n+\tclose(fd);\n+\tif (len < 40)\n+\t\treturn -1;\n+\treturn get_sha1_hex(buffer, result);\n+}\n+\n+static int get_sha1_basic(const char *str, int len, unsigned char *sha1)\n+{\n+\tstatic const char *prefix[] = {\n+\t\t\"\",\n+\t\t\"refs\",\n+\t\t\"refs/tags\",\n+\t\t\"refs/heads\",\n+\t\t\"refs/snap\",\n+\t\tNULL\n+\t};\n+\tconst char **p;\n+\n+\tif (!get_sha1_hex(str, sha1))\n+\t\treturn 0;\n+\n+\tfor (p = prefix; *p; p++) {\n+\t\tchar *pathname = git_path(\"%s/%.*s\", *p, len, str);\n+\t\tif (!get_sha1_file(pathname, sha1))\n+\t\t\treturn 0;\n+\t}\n+\n+\treturn -1;\n+}\n+\n+static int get_sha1_1(const char *name, int len, unsigned char *sha1);\n+\n+static int get_parent(const char *name, int len,\n+\t\t      unsigned char *result, int idx)\n+{\n+\tunsigned char sha1[20];\n+\tint ret = get_sha1_1(name, len, sha1);\n+\tstruct commit *commit;\n+\tstruct commit_list *p;\n+\n+\tif (ret)\n+\t\treturn ret;\n+\tcommit = lookup_commit_reference(sha1);\n+\tif (!commit)\n+\t\treturn -1;\n+\tif (parse_commit(commit))\n+\t\treturn -1;\n+\tif (!idx) {\n+\t\tmemcpy(result, commit->object.sha1, 20);\n+\t\treturn 0;\n+\t}\n+\tp = commit->parents;\n+\twhile (p) {\n+\t\tif (!--idx) {\n+\t\t\tmemcpy(result, p->item->object.sha1, 20);\n+\t\t\treturn 0;\n+\t\t}\n+\t\tp = p->next;\n+\t}\n+\treturn -1;\n+}\n+\n+static int get_sha1_1(const char *name, int len, unsigned char *sha1)\n+{\n+\tint parent, ret;\n+\n+\tparent = 1;\n+\tif (len > 2 && name[len-1] >= '0' && name[len-1] <= '9') {\n+\t\tparent = name[len-1] - '0';\n+\t\tlen--;\n+\t}\n+\tif (len > 1 && name[len-1] == '^') {\n+\t\tret = get_parent(name, len-1, sha1, parent);\n+\t\tif (!ret)\n+\t\t\treturn 0;\n+\t}\n+\tret = get_sha1_basic(name, len, sha1);\n+\tif (!ret)\n+\t\treturn 0;\n+\treturn get_short_sha1(name, sha1);\n+}\n+\n+/*\n+ * This is like \"get_sha1_basic()\", except it allows \"sha1 expressions\",\n+ * notably \"xyz^\" for \"parent of xyz\"\n+ */\n+int get_sha1(const char *name, unsigned char *sha1)\n+{\n+\treturn get_sha1_1(name, strlen(name), sha1);\n+}\n"},{"id":"6791","messageId":"Pine.LNX.4.58.0508032236470.3258@g5.osdl.org","threadId":"1399","inReplyTo":"7vy87i46il.fsf@assigned-by-dhcp.cox.net","subject":"Re: [PATCH] (preview) Renaming push.","fromName":"Linus Torvalds","fromEmail":"torvalds@osdl.org","sentAt":"2005-08-04T05:42:06Z","receivedAt":"2005-08-04T05:42:06Z","isPatch":true,"sender":{"key":"torvalds@linux-foundation.org","avatar":"https://avatars.githubusercontent.com/u/1024025?v=4"},"body":"\n\nOn Wed, 3 Aug 2005, Junio C Hamano wrote:\n> \n> While I have not updated the send-pack <src>:<dst> syntax, I\n> added a horrible hack that some people may love to see.  This\n> removes the need to use git-rev-parse from many commands.\n\nYes, I think this makes sense. We had three different sha1 parsers: \nget_sha1(), get_sha1_hex(), and get_extended_sha1().\n\nNone of the users of get_sha1() really have any reason to want the limited\nform, so I think your patch does the right thing.\n\nNow, for extra bonus points, maybe you should make \"git-rev-list\" also \nunderstand the \"rev..rev\" format (which you can't do with just the \nget_sha1() interface, since it expands into more).\n\nOf course, most people don't tend to use git-rev-list directly, so maybe \nthat's not a biggie, and so git-rev-parse is fine.\n\n\t\tLinus\n"},{"id":"6794","messageId":"7vvf2m2kex.fsf@assigned-by-dhcp.cox.net","threadId":"1399","inReplyTo":"Pine.LNX.4.58.0508032236470.3258@g5.osdl.org","subject":"Re: [PATCH] (preview) Renaming push.","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2005-08-04T08:09:10Z","receivedAt":"2005-08-04T08:09:10Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Linus Torvalds <torvalds@osdl.org> writes:\n\n> Now, for extra bonus points, maybe you should make \"git-rev-list\" also \n> understand the \"rev..rev\" format (which you can't do with just the \n> get_sha1() interface, since it expands into more).\n\nHmph.  That makes sense.\n\nWhat I set out to do when I started ripping extended_sha1 out of\nrev-parse was actually something else.\n\nRemember I was stupidly wondering why \"git log master..gitk\" did\nnot do what I wanted to?\n\nThe reason I started looking at git-rev-parse was because I\nwanted to add \"git log master...gitk\" (three dots) which is\nequivalent to \"git log $(git-merge-base master gitk)..gitk\".\nThat was what I wanted to have when I asked that stupid\nquestion.\n\nBut unfortunately my GIT day this week is over, so the rest is\nfor the weekend.\n"},{"id":"6855","messageId":"7vpssu2ggo.fsf_-_@assigned-by-dhcp.cox.net","threadId":"1399","inReplyTo":"Pine.LNX.4.58.0508032236470.3258@g5.osdl.org","subject":"[PATCH] Teach rev-list since..til notation.","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2005-08-04T09:34:31Z","receivedAt":"2005-08-04T09:34:31Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"The King Penguin says:\n\n    Now, for extra bonus points, maybe you should make \"git-rev-list\" also\n    understand the \"rev..rev\" format (which you can't do with just the\n    get_sha1() interface, since it expands into more).\n\nThe faithful servant makes it so.\n\nSigned-off-by: Junio C Hamano <junkio@cox.net>\n---\n\n rev-list.c |   38 ++++++++++++++++++++++++++++++--------\n 1 files changed, 30 insertions(+), 8 deletions(-)\n\nf22d271a469b65760f73dc483aeb2448619e0ff1\ndiff --git a/rev-list.c b/rev-list.c\n--- a/rev-list.c\n+++ b/rev-list.c\n@@ -457,6 +457,15 @@ static struct commit *get_commit_referen\n \tdie(\"%s is unknown object\", name);\n }\n \n+static void handle_one_commit(struct commit *com, struct commit_list **lst)\n+{\n+\tif (!com || com->object.flags & SEEN)\n+\t\treturn;\n+\tcom->object.flags |= SEEN;\n+\tcommit_list_insert(com, lst);\n+}\n+\n+\n int main(int argc, char **argv)\n {\n \tstruct commit_list *list = NULL;\n@@ -465,6 +474,7 @@ int main(int argc, char **argv)\n \tfor (i = 1 ; i < argc; i++) {\n \t\tint flags;\n \t\tchar *arg = argv[i];\n+\t\tchar *dotdot;\n \t\tstruct commit *commit;\n \n \t\tif (!strncmp(arg, \"--max-count=\", 12)) {\n@@ -523,21 +533,33 @@ int main(int argc, char **argv)\n \t\t\tcontinue;\n \t\t}\n \n+\t\tif (show_breaks && !merge_order)\n+\t\t\tusage(rev_list_usage);\n+\n \t\tflags = 0;\n+\t\tdotdot = strstr(arg, \"..\");\n+\t\tif (dotdot) {\n+\t\t\tchar *next = dotdot + 2;\n+\t\t\tstruct commit *exclude = NULL;\n+\t\t\tstruct commit *include = NULL;\n+\t\t\t*dotdot = 0;\n+\t\t\texclude = get_commit_reference(arg, UNINTERESTING);\n+\t\t\tinclude = get_commit_reference(next, 0);\n+\t\t\tif (exclude && include) {\n+\t\t\t\tlimited = 1;\n+\t\t\t\thandle_one_commit(exclude, &list);\n+\t\t\t\thandle_one_commit(include, &list);\n+\t\t\t\tcontinue;\n+\t\t\t}\n+\t\t\t*next = '.';\n+\t\t}\n \t\tif (*arg == '^') {\n \t\t\tflags = UNINTERESTING;\n \t\t\targ++;\n \t\t\tlimited = 1;\n \t\t}\n-\t\tif (show_breaks && !merge_order)\n-\t\t\tusage(rev_list_usage);\n \t\tcommit = get_commit_reference(arg, flags);\n-\t\tif (!commit)\n-\t\t\tcontinue;\n-\t\tif (commit->object.flags & SEEN)\n-\t\t\tcontinue;\n-\t\tcommit->object.flags |= SEEN;\n-\t\tcommit_list_insert(commit, &list);\n+\t\thandle_one_commit(commit, &list);\n \t}\n \n \tif (!merge_order) {\t\t\n"},{"id":"6811","messageId":"7vwtn1wh8u.fsf@assigned-by-dhcp.cox.net","threadId":"1399","inReplyTo":"Pine.LNX.4.58.0508030808530.3341@g5.osdl.org","subject":"Re: Users of git-check-files?","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2005-08-04T20:59:29Z","receivedAt":"2005-08-04T20:59:29Z","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, 2 Aug 2005, Junio C Hamano wrote:\n>> \n>> How about git-rev-tree?  Does anybody care?\n>\n> Yeah, probably not. git-rev-list does so much more than git-rev-tree ever \n> did.\n\nI will keep git-rev-list; used in Jeff's git-changes-script and\nsome parts of Cogito as well.\n"},{"id":"6814","messageId":"Pine.LNX.4.63.0508042309380.24861@wgmdd8.biozentrum.uni-wuerzburg.de","threadId":"1399","inReplyTo":"7vwtn1wh8u.fsf@assigned-by-dhcp.cox.net","subject":"Re: Users of git-check-files?","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2005-08-04T21:10:56Z","receivedAt":"2005-08-04T21:10:56Z","isPatch":false,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi,\n\nOn Thu, 4 Aug 2005, Junio C Hamano wrote:\n\n> I will keep git-rev-list; used in Jeff's git-changes-script and\n> some parts of Cogito as well.\n\nAccording to my grep's, these files use git-rev-list:\n\ngit-bisect-script\ngit-cherry\ngit-format-patch-script\ngit-log-script\ngit-repack-script\ngit-whatchanged\ngitk\nsend-pack.c\nupload-pack.c\n\nSo better keep it :-)\n\nCiao,\nDscho\n"}]}