The git interface refactoring should be I think the cause for git 2.0.0 release... -- Jakub Narebski Warsaw, Poland ShadeHawk on #git -
We need to avoid user confusion, so making a command that used to do one thing to suddenly do something completely different is a no-no. However, I do not think it needs to wait for 2.0.0. We can start with a separate namespace (or even a separate "Improved git UI project") and introduce the "improved UI set" in 1.5.0 timeframe. If managed properly, the "improved git UI" can coexist with the current set of tools and over time we can give an option not to even install the older Porcelain-ish commands. -
Dunno. I feel this is a bit overboard. Actually the naming problem is rather localized to one command, namely git-pull. In my opinion going with yet another namespace which would rather add to the confusion not clear it. The best way to avoid user confusion is to remove the source of the confusion not let it live. In other words I think we should _fix_ git-pull instead of replacing it. People are already confused about it so simply fixing this command will have a net confusion reduction. Yet we're not talking about "suddenly doing something completely different" either. If git-pull doesn't merge automatically anymore it is easy to tell people to use git-merge after a pull. "You pull the remote changes with 'git-pull upstream,, then you can merge them in your current branch with 'git-merge upstream'." Isn't it much simpler to understand (and to teach) that way? Also I don't think using git-upload and git-download is much better. This adds yet more commands that do almost the same as existing ones but with a different name which is yet not necessarily fully adequate. I for example would think that "download" is more like git-clone than git-fetch or git-pull. Let's face it: HG got it right with pull and push and newbies have much less difficulty grokking it. We screwed it by not using the most intuitive semantic of a pull and locking the word "pull" away is not the better solution given all considerations. Why just not admit it and avoid being different than HG just for the sake of it? Nicolas -
If it were "you download the remote changes with 'git download upstream' and then merge with 'git merge'", then perhaps, but if you used the word "pull" or "fetch", I do not think so. I would be all for changing the semantics of "pull" from one thing to another, if the new semantics were (1) what everybody welcomed, (2) what "pull" traditionally meant everywhere else. In that case, we have been misusing it to be confusing to outsiders and I agree it makes a lot of sense to remove the source of confusion. But I do not think CVS nor SVN ever used the term, and I was told that BK was what introduced the term, and the word meant something different from what you are proposing. You have to admit both pull and fetch have been contaminated with loaded meanings from different backgrounds. I was talking about killing the source of confusion in the longer term by removing fetch/pull/push, so we are still on the same page. That's where my "you download from the upstream and merge" comes from. -
I would kind of like to see "git poll" -- visit all remote branches, fetching objects and tags into the local repository, so that I can inspect changes off-line and merge, cherry-pick, etc. to my heart's content. That would fit the platform integrator's workflow nicely -- "git poll" into a tracking tree, do some merges there (such as backporting a subsystem to a "stable" base kernel), then merge this backport branch to each platform working copy and cherry-pick other changes as necessary. Cheers, - Michael -
But the fact is that HG (which has a growing crowd of happy campers, maybe even larger than the BK crowd now) did work with and got used to a sensible definition of what a "pull" is. This means that their definition is becoming rather more relevant with time than what it used to, and because it is a saner definition than what GIT has for the same word which HG users really have no issue with, I think we really should leverage the "common wisdom" and consider aligning ourselves with them in this case rather than trying to go into a totally different direction. We simply won't gain anything trying to teach people "a pull in HG is a download in GIT". If a pull becomes the same thing for both then it's one less oddball in the GIT interface. Nicolas -
I personally do not have any issue with that, as long as you would help us convert existing users that what was known as pull is not available and new pull means fetching only. If I recall correctly in this thread, you also advocated to always have tracking branches. I am a bit worried about losing the promiscuous pull usage, which can easily become a regression for people like Linus in the integrator role unless done with an escape hatch. -
Guys, before you start thinking this way, the fact is, there's a lot of happy git users. So the reason for using "git pull" is - bk did it that way, and like it or not, bk was the first usable distributed system. hg is totally uninteresting. - git itself has now done it that way for the last 18 months, and the fact is, the people _complaining_ are a small subset of the people who actually use git on a daily basis and don't complain. So don't fall for the classic "second system syndrome". The classic reason for getting the second system wrong is because you focus on the issues people complain about, and not on the issues that work well (because the issues that work fine are obviously not getting a lot of attention). If you think "pull" is confusing, I can guarantee you that _changing_ the name is a hell of a lot more confusing. In fact, I think a lot of the confusion comes from cogito, not from git - the fact that cogito used different names and different syntax was a mistake, I think. And that '#' for branch naming in particular was (and is) total braindamage. The native git branch naming convention is just fundamentally much better, and allows you to very naturally fetch multiple branches at once, in a way that cogito's syntax does not. So when I see suggestions of using that brain-damaged cogito syntax as an "improvement", I know for a fact that somebody hasn't thought things through, and only thinks it's a better syntax beause of totally bogus reasons. I do agree that we probably could/should re-use the "git merge" name. The current "git merge" is an esoteric internal routine, and I doubt a lot of people use it as-is. I don't think it would be a mistake to make "git merge" basically be an alias for "git pull", for example, and I doubt many people would really even notice. But the fact is, git isn't really that hard to work out, and the commands aren't that complicated. There's no reason to rename them. We do have other ...
Those arguments are somewhat flawed. If we stick to "BK did it that way and it was first", then following that logic we would also carry a lot of CVS baggage because "CVS did it that way, and it was the most successful of its kind". Still, we decided not to follow CVS nor BK in many ways already. As for the fraction of people complaining being a small fraction of current GIT users: that is easily explainable by the fact that most people who would have grown the complainers group are simply not GIT users anymore since they were turned away by GIT's current user interface issues. The only complainers remaining are those who see value in the GIT technology but who would like to bring more intuitiveness to the GIT interface instead of going for the alternative The counter part of that is the possibility to fall for the "ivory tower syndrome" where seasoned GIT users feel they are well satisfied with what is currently available and unwilling to consider changes that would reduce the barrier to entry for new users... simply because they are so used to the way things work that they can't see why others have problems Agreed. This is why the current discussion led to a proposition that allows for "pull" to remain as is but to have a "get" version that would Do you have comments on my proposed syntax (that would be implemented I agree with you in general, except for the "pull" behavior which is really really odd. Maybe it made sense in the BK context, maybe it is Agreed again. Nicolas -
Or they are by proxy. *I* don't see that much of a problem with git pull; I can use it without trouble at this point. But I find it difficult to teach to others. My complaints about git pull/fetch/push are by proxy for about 10 other users who aren't on the mailing list but whom I interact with through Git. They don't like pull/fetch/push very much. So count my complaints 10 times. :) Ok, that's still a drop in the bucket of current Git users. But still, I'm sure there are others. I think Carl was recently talking about complaints from some Fedora folks... -- Shawn. -
Agreed. Personally, the first thing that I notice when trying to switch from Subversion to git is the behavior of 'index', mainly in git-diff, git-status and git-commit. For people switching from CVS and SVN it would be much better if the index was hidden behind the scenes by using different defaults: git-commit -a git-status -a git-diff HEAD BTW, currently there's a minor bug: git-diff HEAD doesn't work before you make the first commit. Perhaps this should be special cased. I could personally get used to this, but I'd surely get blank stares from people when teaching them the difference. I guess this is the reason that the GIT Tutorial for CVS/SVN users is talking about _cogito_ instead. (which is very confusing for someone coming to _git_ home page, trying to learn git). Mark -
That's only a _bug_ in your implementation of the synonym for "svn diff" which blindly used "git diff HEAD". "git diff HEAD" is not a synonym for "svn diff" when HEAD does not exist yet, because you are asking "please give me a diff between the tree in the HEAD commit and my working tree files through the index". So if you are doing "git-svnish-diff" Porcelain script, it should notice that HEAD does not exist yet and take an appropriate action. We do something similar in git-status; the porcelain notices and acts differently when HEAD is not there yet. This "there is no HEAD yet" is not related to the index, but I am skeptical about trying to hide the index from the end user. You can make some things map more naturally to systems like SVN and CVS than other things. For example, Nico's proposal to always use remote tracking branches and defaulting to use refs/remotes/ would be a way to match UI of pull/push to another existing system and that would work well (I am not agreeing to the change to make 'pull' not to do the merge which would break existing users -- I am just saying that the result would be self consistent). But things that have difference at the concept level, I suspect no clever mapping to hide the differences would work well. The index is quite central to the way git works at the concept level, and I think it is doing disservice to the end user to try hiding it forever from them and failing to do so, rather than being honest and teaching them the concept upfront. But me thinking so does not necessarily mean you are forbidden from trying. Your efforts may result in a system where the index is totally invisible and the end user never has to know about it. -
I agree with what you are saying about the index. But in git-gui I found myself writing code on Monday which tries to hide the index from the user unless he/she requested that the index be made visible. The reason is there are some users who I'd like to give git-gui to who I'm not sure I trust to make sure their index is in sync with their working directory before they commit. In some cases I'm lucky that the user even knows what directory their file is stored in. :-( Yes, there really are computer users who are afraid of directories and command lines. I probably could try to teach them to make sure the final file is included in the index before committing, but I think that for most of them they would find this to be just another couple of mouse clicks they have to perform before every commit, meaning its something that the #$@!*@!*@$# tool should just do for them. -- Shawn. -
My "implementation" is taken from git-diff man page. It seems obvious that the situation before the first commit is just a special case if I agree, this is a separate issue. Mark -
On Wed, 15 Nov 2006 20:05:27 +0100 IMHO this is really bad. Pasky runs the Git web site and feels that Cogito comes hand in hand with Git. When I asked him about it he mentioned that Junio had approved. But it's very confusing to click a link that purports to show you how to use Git and get shown a bunch of Cogito stuff. Git is confusing enough for new users without "Git" and "Cogito" being mixed without comment on the Git webpage. At the very least, the links should be changed to "Cogito for CVS/SVN users". Sean -
I'm a happy user, doesn't mean I wouldn't like changes. In fact, by that argument, that there are happy users means that there is no need to ever make That's awfully like the argument I hear off my bank whenever I complain to them too - "well lots of other people don't complain so we must be right". The people who complain are a subset of the people who have complaints. I don't think never changing is a good argument - leaving aside the actual changes under discussion - in another 18 months lets say there are double the number of git users, and 18 months after that double again - in that case the On the one hand you're arguing that git syntax is easy to learn, and on the I don't think so. Mainly because the proposed new git pull would be a subset of the existing git pull. It's not changing function, it's just reducing in function. Andy -- Dr Andrew Parkins, M Eng (Hons), AMIEE andyparkins@gmail.com -
I'm saying that people who are new to git will _have_ to learn new concepts ANYWAY. I don't think the naming is the hard part. The fact is, git is one of the very few (essentially _only_) SCM's that make it very clear that all real operations are local and that if you want to work with other repositories, you have to "fetch" those into local branches first. The fact that "pull" exists at all is really just shorthand. If people have trouble explaining this to others, and have trouble grasping "pull", then I will bet that the _real_ issue has nothing at all to do with naming at all, and the real issue is that people are being _taught_ the concepts in the wrong order. Before you learn "pull", you should learn "fetch". Don't even _mention_ "pull" until the person got what "fetch" means. Because the fact is, "fetch" is really the much more fundamental operation, and once you really understand what "fetch" does, "pull" is obvious. So I'll argue that the problem isn't naming, the "problem" is really that git has a few fundamnetal concepts that people aren't used to. The most fundamnetal of those is the notion of the local branch-space. EVERY other (broken) SCM has branches as being some kind of totally idiotic separate subdirectories, or doesn't really support branches at all (ie neither BK nor CVS really support "branches" - even if a concept of that name exists in CVS, it has nothing at all in common with the git model of branches). But once you understand branches, and understand "fetch" (and it really isn't _that_ complicated: fetch really does exactly what the name says, so if you understand local branches, you will understand "fetch"), then it's a much smaller step to explain "pull = fetch + merge". But I bet people don't teach it that way. They _start_ by teaching "pull". Right? Linus -
"git fetch" is certainly the right thing for the platform integration role, in which one is trying to maintain a series of integration branches which track the bleeding edge of some subsystems while keeping the core stable on each branch. This is not as impossible as people make it out to be, but there certainly isn't much place for automatic merges to _persistent_ branches. It's fundamentally a backporting and cherry-picking effort, and the git workflow puts it where it belongs: in the local repository, where _transient_ branches can and should be created and destroyed casually to track exploratory efforts. These may include automatic merges and even cruder techniques (git diff, hack on patch, apply patch). Once you figure out which bits you actually want to backport, you go back to a fresh branch and cherry-pick the same bits with the tool instead of manually, so that there is less noise in future merges. When you've tested a little, you merge this branch to the persistent branch that other repositories track. Cheers, - Michael -
I'm saying that even if you _never_ end up using "git fetch" ever again (because in practice you always want to do a "fetch + merge == pull"), people who teach others the concepts and usage of git should probably start by talking about "git fetch". Then, when the user says (and he obviously will say this) "but I don't want to just fetch the other persons work into some local branch, I want to actually get it into _my_ branch", you say "Ahhah!" and talk about how "pull" is a shorthand for first fetching and then merging the result into the current branch. See? Once you explain "fetch" to somebody, I can pretty much guarantee that they'll explain "pull" to themselves without you having to even work at it. And then they'll probably happily use "pull" ever after, and never worry about fetch, but now they'll understand the _concepts_. It's only if you start the other way around that "pull" vs "fetch" vs "push" become confusing. If you _start_ by explaining branches (and you might use "gitk --all" on a small project as a visualization tool), suddenly the concepts aren't all that complicated. Sure, then you have to remember two words ("pull" vs "fetch"), but I'm pretty sure that the thing that makes people confused is not the words themselves, but their lack of understanding of the concepts behind them. Linus -
Actually I believe it would make things even clearer if "merge" was taught at that point. Only when the user is comfortable with the separate notions of fetching and merging might the pull shorthand possibly be mentioned. Nicolas -
I agree. I just expect that "merge" is such a simple concept that it
doesn't really need a whole lot of explaining.
People kind of expect merging to be hard, but I think it's because CVS et
al have tought people that merging is _painful_. I don't think it's a very
complicated concept per se, especially if you have explained branches with
gitk already.
But yes, the order should be:
(a) explain what "branches" mean in git (and in that situation, "fetch"
is very natural - I think fetching itself is probably easier to
explain than "branches" are).
(b) once you've explained branches, the notion of "merge" comes next, and
I _think_ that is very obvious. This is where UI issues come in,
because "git merge" is really a totally internal program with a
pretty horrid UI, but I think we could fix the syntax, and even with
the current syntax you can really just gloss it over, because nobody
is really going to care.
(c) once "fetching branches" and "merging" have been explained, "pull" is
really pretty damn trivial, and in fact, if you then explain that
it's just easier to do "git pull . branchname" than to use "git
merge", I think people may just even agree with you.
I think I saw that particular discussion on #git: somebody didn't expect
"git pull . branch" to be the way to merge. And again, I think it's
not _really_ because "pull" is hard to understand, it's because people
haven't been walked through the thing in this way.
Once you understand local branches, fetching and merging, it's actually
_easier_ to explain why we merge even local branches with "git pull .":
you just tell them that this way you can use the same command regardless
of whether you're merging something local or something remote. Again, if
it's explained that way, I bet a lot of people react with "ahh, that's
clever", and _like_ the fact that they only really need to learn _one_
command, instead of learning two.
See? Explain it ...Well, one of the problems is that with current git I can teach, (and I have), that there's a conceptual: pull = fetch + merge But then shortly after I have to teach an interface notion: merge = pull . So there's this goofy circular notion that people end up with mentally. If we fix it so that a local merge really is performed with "git merge <branch>" instead of "git pull . <branch>" then teaching pull=fetch+merge really is a lot easier. In the meantime, pull would still be useless to me, I think. But maybe that's just the "default branch to merge" selection being broken. If There's a piece missing here, namely the mapping between remote and local branch names and any notion of "tracking branches". I think a sane story for that is still being invented, (or if it exists now, I No. It's really, really broken to use "pull ." for local merging. Not a feature at all. We just got done establishing that pull is a shorthand for doing fetch+merge, so reusing it when there is _no_ fetch at all is insane. You just established quite clearly hat git has a huge advantge over all other systems by having a model that everything is fetched in and then worked with locally. I agree that this is a major selling-point of git, and I'm also baffled that systems like bzr and hg try so hard to push every branch into a separate repository. But I think that git's "work with everything locally" story is undercut a bit by regular usage being to use a transfer-inducing command like "pull" for a totally local merge. Anyway, I think we all agree that we'd really rather have "git merge <branch>" be usable for local merges, so let's get that in place and Totally agree. -Carl
I am wondering if that could be "git merge <committish>..."
instead. I do not care too much about the ... part (i.e. an
Octopus), but I often find myself doing:
git checkout next
git merge "Merge early part of branch 'foo'" HEAD foo~3
when earlier part of "foo" topic are worthy to be in 'next' but
Have you looked into per-branch configuration for default merge
source recently? It might not be documented well enough,
though, because I do not use it myself, but you should be able
to improve on that (meaning both documentation and setting up
the defaults upon cloning and fetching).
-
Indeed, what? That means that updated "git merge" (not the current one) would not be able to assume it's parameter is a branch name, and still has to come up with the merge message "Merge <branch>". Merging only within the local branch namespace already has the problem you need to solve to come up with a nicely formatted "Merge <branch> of <remote repository>" some way. I am not saying that this is unsolvable (you can look at remotes/ files to see what remote tracking branch the branch is about), but something you need to keep in mind when implementing the improved "git merge". -
Right. But that is an _implementation_ detail, not a usability issue. Nicolas -
Often, it would be a branch or a tag, so no problem there. For commits in general, it should not be hard to compute the set of branches and tags the commit is part of, and in the (probably) common case where this set has exactly one element, the problem is solved. For the remaining cases, it should not be too horrible to ask the user to describe what is being merged. -- Karl Hasselstr
This is why I would suggest teaching the _concept_ of the "merge", and not the actual command. I don't think you should basically ever use the "git merge" command itself, not in teaching, and not in real life. So after talking about branches and having taught people to use "git fetch", the next stage is not so much to teach people to use "git merge", but to explain to them the _concept_ of merging. I really think that's a fairly quick thing, partly exactly _because_ you shouldn't at that point need to worry about syntax or details or anything like that at all. You just tell them that there's a notion of "merging" two branches by joining them together and havign the result have the changes from both branches. So it's a _conceptual_ issue, and that's why I said I think you should just totally gloss over the whole issue of "git merge" syntax. Once you've explained the _concept_ of merging, you then introduce the command to actually _execute_ the merge: it's "git pull". See? No circular thinking at all. One is a _concept_ ("join two branches together by including both in the result") and the other is a command ("pull will fetch the remote data if any, and merge it into the current branch"). If you explain it that way, then _obviously_ if you don't need to fetch any remote data, doing "git pull . xyzzy" will merge the local branch "xyzzy" into the current branch. Linus -
I think that's just and accident of git-merge having such a bad syntax, (requiring a merge message, not using -m for that, requiring two heads instead of defaulting to current, etc.). So the result is accepting another bad syntax "pull ." for an operation that really is I think we'll be doing better when there is a stronger correlation between the concepts of the operations and the command names for carrying them out. Plus, when I'm teaching "fetch everything first, then manipulate it locally", (which is what I teach, since that's the only way I use git), then the "." looks really out of place when I teach the 'merge' command. I end up saying, "Oh, that's there because you could do the fetch and merge all in one step if you really wanted, but I never do that.". That doesn't work. I know I went looking at the git-merge documentation when I started to learn git. "It can't really be this hard, can it?" was my reaction to it. And then only after attending a tutorial did I learn that "pull ." is the way it's really done. That's nothing more than a user-interface trap for new users, plain and simple. The real fix is to stop glossing over git-merge and just give it a usable syntax. -Carl
Ditto. In every way. I've taught the same fetch first, then merge strategy. Nobody I know in meat-space pulls from a remote URL and merges in one shot; they always fetch locally, look at the incoming changes, decide if its worthwhile/ok, *then* merge with "git pull . branch". The "." looks out of place for everyone... -- Shawn. -
Actually, with different people involved it's _much_ better to do it in
one shot.
Why? Because doing a separate "fetch to local space" + "merge from local
space" actually loses the information on what you are merging.
It's a lot more useful to have a merge message like
Merge branch 'for-linus' of git://one.firstfloor.org/home/andi/git/linux-2.6
than one like
Merge branch 'for-linus'
which is what you get if you fetched it first.
Of course, in a situation like git itself, where most of the merges are
stuff that Junio has had pending in his own tree ('maint' branch etc),
things are different. But in a system where people actually use separate
trees, there really is an advantage to consider the fundamental operation
to be the "pull", not the "merge".
Again, the kernel really is more distributed than most projects, but this
is another thing people should recognize: git has been designed for "true
distributed development". Not the "fake" kind. Not the "I merge mainly my
own branches" kind of thing. Truly distributed.
And in a truly distributed situation, "pull" is strictly more powerful
than a separate "fetch" + separate "merge".
In other words, an SCM that does "pull" is _better_ than an SCM that does
"merge". You can implement "merge" as a special case of "pull" (which we
do), but you cannot conveniently do it the other way around without having
to tie them together some other way (ie you could have a "remember the
last place we fetched this branch from in order to tie the fetch and the
merge together" - but please realize that that is exactly what "pull"
_is_).
So I will generally do a "git pull" (possibly followed by a "git reset
--hard ORIG_HEAD" if I decided it wasn't good) over a "git fetch" + "git
merge". Exactly because the "pull" operation is actually more powerful.
Maybe people who aren't in my position don't always appreciate the _power_
of git. The reason "merge" is a second-class citizen is simply because IT
SHOULD ...That is an implementation detail that should be easily overcome once the notion of tracking branch with URL attribute is implemented. Then it will be really easy to notice whether the branch argument is a local branch or a tracking branch with remote reference. Nicolas -
Nope. I simply don't _have_ those branches. Why? Because the kernel is _distributed_. There is no central place (certainly not my repository) that tracks all the possible branches that might get merged. In other words, I repeat: in a TRULY DISTRIBUTED ENVIRONMENT it makes more sense to have a "pull" that fetches and merges, over something that fetches separately and then merges. Because in a truly distributed environment, you simply DO NOT HAVE static branches that you can associate with particular sources. See? And the thing is, I think the git design should be geared towards true distribution. It should NOT be geared toward a fairly static set of branches that all have a fairly static set of other repositories associated with them. Can you see the difference? I'm personally convinced that one of the reasons people tend to use git in a centralized manner is just a mental disease that has its roots in how they used _other_ SCM's. I don't want git design to be polluted by such a centralized notion. So to repeat: you can always make "pull" boil down to "pull from myself" (aka just "merge"), but you can _not_ make "fetch + merge" boil down to "pull" without meking up extra state to track separately. In other words, "pull" really is the strictly more powerful operation. Linus -
[...] OK fine. git-pull is there to stay and let's make sure it remains the same. Let's see if, for example, git-merge can be made more useful in the mean time for those evidently inferior people that would prefer an interface that maps more closely to the actual operation that is being performed. And although I do understand what "pull" does, I think I should qualify myself as one of those inferior people nevertheless since /pull . blah" really irritates me. OK I must be really dumb to let myself being disturbed by such an insignificant detail... but apparently I'm not alone. But I promise to never change the "pull" behavior if I ever attempt to fix the "merge" command for the inferior mortals as myself. All power to those with superior minds shall never be removed. ;-) Nicolas -
Full ACK from a platform integrator's perspective. Local merge is great for trial runs but the history in a persistent branch should be as self-contained and self-explanatory as possible. It shouldn't depend on what I name local tracking branches, which are just a convenience so that I can still do trial runs when my connectivity is broken. I don't have to manually log the _mechanical_origin_ of a given delta; git does that for me, and mostly just DTRT when the same delta arrives via several paths. When I use git pull from a remote branch (with or without an entry in remotes/heads, which for this purpose is just shorthand), I don't have to manually log what conflicts I have and haven't resolved, either; I must have assimilated whatever I cared about in the remote branch's history up to that point, because as long as there are things in that remote branch that I haven't decided how to handle, I stick to cherry-picking. Obviously, fetch to local space is great (especially when you spend some of your working hours behind a firewall that blocks outbound TCP 9418). Fetch from local space is also great, when the local space you are fetching from reflects local work (such as a sync point and reconciliation of several upstream sources, which then needs to be ported forward or back to the chosen core version for each platform). Fetch from a local space that is just a tracker for remote work is not great, because it doesn't capture the editorial decision implied by a remote pull: I looked at what the remote branch had to offer as of this date, systematically decided which bits did and didn't belong in the branch to which I was pulling, and pulled. The record of that pull becomes a first-class object because it's attached to an actual content delta in the target branch. So it propagates into branches that pull from it. Pulling this delta into another branch is different from cherry-picking a feature delta; it implies acceptance of the reconciliation and editorial work ...
I think it's unfortunate that git was originally written by Linus, since he so obviously is "the guy at the top of the pyramid" in many more senses than just "Linus said this and that patch was OK to commit", since git was designed to work like king Arthur's round table; "Linus is in the same circle as me, so ofcourse we help each other out". All suggestions I've been reading about tracking branches, separate-remotes and whatnot have their merit. If any of it gets implemented, I'd still like to be able to do one-shot pulls from remote repos *without* creating specific tracking branches for it. It's extremely useful to fetch other peoples topic-branches into my own "master" (or topic-branch) when I trust their changes to be good. Please consider that when you're hacking away on whatever changes to do. -- Andreas Ericsson andreas.ericsson@op5.se OP5 AB www.op5.se Tel: +46 8-230225 Fax: +46 8-230231 -
There's more information in the first, sure. But I absolutely don't accept that it's necessarily more useful, and definitely not that this is a good argument for using pull with a remote branch instead of fetch followed by merge with a local branch. First, the pull may just fast-forward in which case there's no message at all. And we've been through that topic enough recently that we all know that no important information is lost by not doing any separate recording in that case. So you can't turn around and argue that the remote URL information is suddenly important when it just so happens that it's not a fast I don't buy it. In my usage, I have several different remote repositories I'm interested in tracking, each with any number of branches. What I really want is an easy command that fetches all of those branches, (even new ones that I've never heard about---but never any of their "tracking branches" that wouldn't be of interest to me). And I want to do that once, to get the online-access-required part over with and get all the data into my local repository where I can start working with it. As for the URL from which I'm fetching all this stuff, it's really not interesting to me at all. The URL for "Keith's stuff" keeps changing anyway---I have no interest in recording that. But I do think it's worth recording that the commits came from Keith's repository. I do that right now with a keith/ prefix for his branches. It could also be done by bringing in his .git/description during the fetch and storing it somewhere. But I honestly don't see how storing something like that during would make the system any less distributed in any sense. -Carl
When it's a fast forward, the puller hasn't had to make any judgment calls, so there's no editorial history to record. When it's not, but the puller chooses to retain the result on a persistent branch, that _is_ an editorial decision (even if the result of the auto-merge is What do you want all of those branches for? They haven't been published to you (that's a human interaction that doesn't go through git), so for all you know they're just upstream experiments, and doing things with them is probably shooting yourself in the foot. I do agree that a robust form of "for b in .git/remotes/*; do git fetch `basename $b`; done" would be a nice bit of porcelain. The entries in .git/remotes would probably need to grow a "Fetch-options:" field so that you could choose whether or not to follow tags, etc. Patch to follow. Cheers, - Michael -
The same "what do you want them all for" question could be asked of git-clone which also fetches all available branches. I really just want to be able to easily watch what's going on in multiple repositories. I want to be able to just say "git update" (or whatever) and then be able to list and browse and explore the stuff locally. Yes, there's still outside communication that's necessary, but with the ability to easily track all the remote branches that communication can be even less formal if I can easily browse and explore things locally. For example, I might not even know the name of the branch: Me: Have you pushed a branch for your new work on the frob-widget? Friend: Yes And then I can "get fetch" and see "cool-new-frob" come in without having to be told that name. Or I could have even just fetched without the specific communication if I was already expecting it for some reason. -Carl
I have no objection to this if it is done in a controlled way that does not make life more difficult for people who work with multiple remote repositories. And I think "git fetch" is the tool for what you want if enhanced properly; see Linus's message that explaind that we already have that support in "manually configurable" form but initializing and maintaining the configuration is currently all manual and can be improved. -
That's fine with me. Maybe I didn't explain this well before, but my desire is exactly for this to work with multiple repositories. Specifically, what we have in cairo is a "central" shared tree that many people push to. But we only have two branches there, (one for bug-fixes only for our stable releases, and one for ongoing development of new features, and that only of stuff that's well cooked). So that tree looks and acts an awful lot like our cvs tree back in the past. It's often very linear and often fairly boring to look at in gitk. Meanwhile, all the really interesting stuff happens in personal repositories where people have their own branches for stuff that is still getting cooked. This is what's a lot more fun to watch, and there's a lot more distributed back-and-forth that goes on here as people collaborate on things. And it's all this kind of collaboration that cvs never helped with at all, but git has been great. So, what I want is both "git update" for the central tree. I said we only have two branches, but that's really only two that are active---the "stable" branch is actually a new branch after every major release. It was 1.0 for a while, is 1.2 now, and will be 1.4 later. So I want "git update" to automatically pick those new branches up as they get created. Meanwhile, I also want to use "git update" to track everything that people are working on in the more wild personal trees. So, yes, I do want "git update" to be able to track lots of remote repositories in a sane way. What I have been doing up to this point is a little script I wrote that does git-ls-remote on the repository I want to track and writes a .git/remotes file to bring in all their branches. So if I want to see what behdad is up to, I first refresh his .git/remotes file with my: cairo-git-setup-remotes behdad then: git fetch behdad And I end up with a bunch of branch names with "behdad-" prefixes that I can explore or blow away if I'm no longer interested, (could have used a ...
Hi,
I introduced the remote.<nick>.{url,fetch,push} entries into the config
with the goal to enhance -fetch to remember the current command line with
a setting. I was the only one to find that useful.
BTW I still would argue that it is better to write the remote information
into the config, because you have a saner way to manipulate that from
I think a message like "This remote branch no longer exists. Maybe you
want to use 'git branch -d <branch>' to remove it locally?" should
IIRC this idea was rejected, but I would find it useful. Especially with
what Han-Wen said: you can store the branches you fetch with "git fetch
First thought was: it is only useful if you want to track multiple
repositories. But next thought: if you mark the correct remotes in every
of your local repositories, you don't have to remember which nick your
upstream has. Yeah, I like it. But maybe do it as "git fetch --update" to
avoid more cluttering of the bindir?
Ciao,
Dscho
-
With separate-remote layout, this can be done without risk of tracking refname clashing with local refname, which was the primary reason for an earlier reluctance. While separate-remote layout also solves Carl's "do not want to track tracking branches remote has" problem, local branch namespace can have both for-others (not necessarily "public" but could be "for colleagues") and throwaway branches, so --all is probably not the right thing to do in most cases. But I am Ok with the approach of seeing how well it works out in practice by doing the simplest "--all" and giving options to restrict it later. -
I'm *fully* in favor of the remote.<nick>.{url,fetch,push} entries
in the config file. I've pretty much switched every repository to
that format at this point.
In writing git-gui I'm finding it much, much easier to manage
things through repo-config than to do any mucking around in the
.git/remotes directory. Yes, the remote files have simple format,
but I can get everything in one "git repo-config --list" pull it
all into a Tcl array and work with it; using .git/remotes means I
have to open the file and read each line too. :-(
--
Shawn.
-
This already should be the case if you use separate-remote. I haven't run "clone --separate-remote" myself for a long time, but the design was certainly to make it behave that way. Specifically, map everything in refs/heads/ at remote to refs/remotes/$origin/ with corresponding names, one-to-one. I do not see much reason to change the mapping of master:origin which is done for the traditional layout. The traditional layout is not suitable for your workflow anyway, and that is why you prefer separate-remote layout for your project, and I fully These three are easily done for separate-remote layout but at that point you would not want --all but more powerful --mirror (or --update if you want to use that word), which goes the whole nine yards of noticing disappearance of remote branch, making matching deletion of local tracking branch, updating .git/remotes, etc. I've muttered something similar in a nearby I would prefer this to be kept in contrib/; it feels like it is I muttered something less elaborate in the nearby thread. Message-ID: <7vr6w78b4x.fsf@assigned-by-dhcp.cox.net> Message-ID: <7v64dev88t.fsf@assigned-by-dhcp.cox.net> The part that deals with manual configuration (the last point in the first message, and the second in message its entirety) is something your workflow would not need nor want to worry about, but I think it is necessary for different ref namespace layouts and different workflows. I think the automatable part (the first two points in the "sensible thing to do" list in the first message) is very relevant to what you talked about in your message. -
On Wed, 15 Nov 2006 14:52:32 -0800 Agreed 100% There's just no good reason to hide the user level merge command inside of pull. Sean. -
On a conceptual level, can we not perhaps explain that if pull = fetch + merge then merge = pull - fetch and that the latter (pull - fetch) happens to be expressed with the interface as 'git pull .' ? My 2 cents. J
Actually, that's not true. Mercurial has local branches, just as git does. Some people choose not to *use* this particular feature, and use the BK style repository == branch, but that's mainly because it's conceptually easy for them, and a number of BK refugees are very happily using Hg. It's probably because of the BK refugee population that after you do an hg pull, it will warn you that you need to do an "hg update" in order to merge the working directory up to the latest version that was just pulled --- and this change was made precisely because Hg supports local branches, and merging with the current branch isn't always the It's just that the semantics are different, and many developers have to use multiple DSCM's, depending on what project they happen to be developing on. So the reality is that there are people who have to use bzr, git, and hg, all at the same time. And while eventually newbies will figure out and remember that "git pull ." == "merge", the naming is simply confusing, that's all. (What does "pull" have to do with "merge"? It's not at all obvious.) For somoene who uses git full-time, and to the exclusion of all other systems, I'm sure it's not a problem at all. - Ted -
It seems we should, cheaply, be able to avoid a large part of the
confusion by
* Mentioning git-fetch before git-pull in all documentation newborn
gitizens are likely to come across. Most git-users aren't Linus, and for
every successful project the maintainers are outnumbered 100 to 1 by the
contributors. Those projects successful *because* maintainers are
heavily outnumbered so we should make it easier for contributors by
teaching them the right things from the start and possibly have a
separate man-page for maintainer (git-{maintainer,developer} man-pages,
anyone?).
* Creating "git update" which might possibly be an internal alias to
"git pull", except that it should read .git/remotes/* by default unless
a specific remotes-file is specified.
* Renaming git-merge to git-merge-driver
* Implementing a git-merge that actually does what its name implies,
possibly by making it an internal alias to pull, but with these differences:
- It always merges into your current branch.
- It understands "git merge branch" as well as "git merge . branch".
This is just the very low-hanging fruit. If we take these steps and let
things cool down a bit, it would probably be proper to take a fresh look
at this in a couple of months.
--
Andreas Ericsson andreas.ericsson@op5.se
OP5 AB www.op5.se
Tel: +46 8-230225 Fax: +46 8-230231
-
However, I also think it might make sense to talk about the _simple_ form of "git pull" first. The form I use is actually a lot simpler (conceptually) than the "short" form. When you do git pull <reponame> <branchname> there are very few things that can confuse you (although trying to do it without a current branch at all is apparently one such thing ;). There are no local branches to worry about, and there aren't any issues about what the default repository or branchname on the remote side would be either. So in many ways, if you use this format, you simply never have to worry. You may have to _type_ a bit more, so it's not the short or concise format, but it sure is the _simple_ format. There simply isn't anything to be confused about. And yes, I actually tend to use this even for project that I don't develop on, partly because the defaults for the short and concise formats are bad. For example, I follow the "modesetting" branch on the xorg intel graphics driver tree, and because I'm always on that branch, what I do is git pull origin modesetting which works correctly (while "git pull" would _not_ have done the right thing: it would have picked the right repository, but it would have picked the "master" branch of that repository, not the "modesetting" branch). And notice how I don't do _any_ development there, I just follow that branch. The "merge" will obviously always be a fast-forward, but that's Well, as mentioned, I think even for non-developers, doing pulls with explicit branchnames is actually perfectly sane. Linus -
Yes, that's what the user almost always wants. The UI problem here is that the conceptually simpler form is syntactically longer, (which means users aren't likely to find it). So if we can just get <reponame> and <branchname> to default correctly, (based on the current branch name, and clone/fetch/pull history), then the conceptually simple form ends up syntactically simple as "git pull". And I definitely don't have any problem with that. I'd love to be able The behavior is sane, but having to always type the branch name specifically because it never changes... that's a user-interface bug. This is a good example of the kind of thing I wanted to hit when starting this thread. I don't think there are any big conceptual changes needed in git to make it easier for new users. But there are little things that are problems that really should be fixed. Wouldn't it be great to have the following exchange: User: How do I track on-going development in a branch? Master: Use "git pull" Rather than: User: How do I track on-going development in a branch? Master Use "git pull origin <name-of-branch-you-are-already-on>" ? -Carl
Yeah.
And this is something I absolutely agree with. Our default branches for
"pull" are horrible. You can "fix" it, but you can only fix it by adding
_explicit_ branches to your .git/config file by hand, so I don't think
that's actually a real fix at all. We should just fix the default (where
even a "I don't know what branch you want" _error_ would be preferable
over the current situation).
Along with the "git checkout <tag>" thing, I think these two things are
Yeah. Each branch should
(a) have a "default source" initialized on the initial "clone"
(b) have a way to set the source afterwards
(c) error out if you do just a "git pull" or "git pull remotename" if
there is no default branch for the current local branch for that
remote.
We actually have (b) in a weak form right now ("weak" because it requires
you to manually edit the config file: we've got the mechanism, but not a
nice UI for it), but (a) and (c) are just broken.
And yeah, we should allow pulling into a branch that hasn't been
initialized.
Linus
-
On Thu, 16 Nov 2006 09:30:47 -0800 (PST) This would be _great_. You just shouldn't have to hack at the .git/config file to get reasonable default sources after a clone. Or even for that matter after fetching a new branch into an existing repo. Sean -
We usually use the word "regression" to refer to that kind of change. I think it makes a lot of sense having command x that does essentially the same thing as the current fetch but with more usability enhancements and more convention as built-in defaults, and another command y that does what the current 'pull .' does but with more usability enhancements and more convention as built-in defaults. I agree that kind of UI improvements would make it easier to explain to new people. Calling x "pull", however, breaks the existing users and documents, and causes confusion. I really do not think you can argue with that. That's why we are talking about using an uncontaminated word And I think Linus is right in pointing out that there are other problems that are equally or even more pressing than _renaming_ to break things for existing users. I personally do not think the current fetch/pull confusing, and I do see real downside in _renaming_ them, but I am open to the current get/put discussion because I think the new commands' semantics may be designed to match newcomers' expectation better (it's to match tools to newcomers instead of teaching them the new language of the land) and I do not think that approach would break existing users and documents. For some things "matching tools to newcomers" would not really work, though. For example, I do not think you can get away with hiding index forever if you want your users to do real work in a workflow that involves merging and cherry picking. -
that's not a good argument; the set of git users is a small subset of
those that looked at git, and dismissed it because they couldn't wrap
their heads around it. It's worth trying to get those on board by
fixing the annoying little issues that have popped up in this thread.
The technical base for GIT is excellent, and the only reason for not
using it is its arcane interface.
A version control system is often only tangentially related to the real
work that needs to be done, so the incentive to learn it well is small,
and a steep learning curve only makes it worse.
FWIW, I regularly mess up with the differences between fetching, pulling
and merging. In particular, having to do a two step process to get
remote changes in,
git pull url-to-server master:master
..error message about not being a fast-forward..
git pull --update-head-ok url-to-server master:master
..still an error message about update not being a fast-forward..
(sigh)
git pull url-to-server master:scrap-branch
git pull . scrap-branch:my-current-branch
(make mental note of deleting scrap-branch)
--
Han-Wen Nienhuys - hanwen@xs4all.nl - http://www.xs4all.nl/~hanwen
-
Sigh indeed. Why don't you do the simple and obvious git pull url master or "git pull url" if you already know the master is the branch you are interested in. The more advanced form of using tracking branches are there and documentation talks about them for completeness but that does not mean you have to use it. -
It is not all evident from the git-pull man-page that this is the Because I usually replace verbose commands with shortcuts only when I understand exactly what the shortcut is. To me it's very unlogical that master:current-branch doesn't work, but master: does work, and does what I'd expect master:current-branch to do. Interestingly, doing pull ..url.. master:HEAD also doesn't merge into the current branch, but rather creates a bogus refs/heads/HEAD I use the remote:local syntax, because I started using GIT in scripted compiles from copied branches of remote repositories. There the explicit remote:local statements are necessary because there is no default branch. -- Han-Wen Nienhuys - hanwen@xs4all.nl - http://www.xs4all.nl/~hanwen -
In the git user poll a few months ago, many people recommended "everyday git" as a good cheat sheet, and indeed it does not talk anything about directing the underlying git-fetch to manipulate tracking branches by giving explicit refspec pairs to git pull. You are obviously tripped by both the overeager manpage (but manpage should strive to be complete so you cannot really blame it) and less than optimally organized tutorial style documents. I myself do prefer, when learning a new tool, to use longhand until I understand the shorthand, but that attitude requires a true commitment to learn the tool, and most people do not go that route. Tutorial style documents tend to give the commonly used shorthand first for that exact reason. Shorthand to give only the branch name to fetch and merge immediately without using a tracking branch is equivalent to longhand "branch:" as you found out, so if that was what was desired then people with the attitude "before understanding what longhand does I prefer using shorthand" like myself and you would have liked to learn "git pull url branch:" notation from Tutorial. But I think we _are_ minority. People would not want That shows that you did not understand what fetch does. Maybe you do now, but a very natural consequence of directing fetch to update tracking branches with the colon notation is: - "pull url master:master", while on master, is almost always wrong and not something you would want to do, ever. "fetch --update-head-ok url +master:master; reset --hard HEAD" If you perhaps wanted to ask "is there a better way to do what I've been doing?", then I am willing to think with you to come up with an answer. Unfortunately, however, I do not understand the above paragraph, so I'd refrain from commenting on it in this response. -
Junio C Hamano <junkio@cox.net> writes: Eh, sorry, "prefer to use longhand until I understand what is -
Sorry, I must have been very grumpy mood when I wrote the
message (cf. Pasky's utterance on #git a few days ago). What I
wrote was a bit incoherent, so here is an attempt to clarify.
I should point out that the colon separated refspec pairs you
can give to "pull" was designed with considerable thought; it is
not a convenience hack that we give them to "pull" that "fetches
and merges". Linus's and Michael's other messages in this
thread may seem to be saying that using tracking branches is not
a kosher way to use git, but I do not think that is a correct
interpretation of their messages.
The workflow that does not use any tracking branches is the
simplest and truly distributed way as Linus says. The command
recommended in "everyday git" document:
git pull $url $branchname
is the most natural way to express it, and simplest variant that
you do not have to say anything "colon" in it.
However that does not mean it is a bad practice to use tracking
branches. Sometimes it is handy to be able to refer to what you
fetched from the remote the last time, possibly which is what
you merged into your branch if that last fetch was done via "git
pull", so that you can later examine its history without your
own development. For that purpose, you need to store what you
fetched in your local refs/ namespace, and that is what tracking
branches are.
The workflow that fetches to tracking branches and then merges
within local repository as two separate steps loses the true
origin information ("Merge branch 'foo'" vs "Merge branch 'foo'
of git://git.bar.xz/foo.git"). That's the reason why not just
"git fetch" but also "git pull" take the colon separated refspec
pairs to direct git to update the tracking branches when "pull"
happenes. The longhands are cumbersome to type all the time,
and we have shorthand, both to store URL: and Pull: lines in
remotes/ hierarchy, and also $branchname alone is a shorthand
for saying "${branchname}:", meaning "do not use a tracking
branch to ...And I've said this again, and I'll say it once more: that has basically _nothing_ to do with whether you spell "pull" as "pull" or "merge". The reason people have trouble wrapping their heads around git is because they have been braindamaged by CVS and SVN, and just don't understand the fairly fundamental new concepts and workflow. That's totally different from then arguing about stupid naming issues. Peopel seem to believe that changign a few names or doing other totally _minimal_ UI changes would somehow magically make things understandable. I claim that isn't so at all. The fact is, git is different from CVS and SVN, and git _has_ to be different from CVS and SVN. It has to be different because the whole model of CVS and SVN is simpyl fundamentally I claim that those "annoying little issues" are totally made up by people who had trouble wrapping their minds about git, and then make up reasons that have nothing to do with reality for why that might be so. Let's face it, you could just alias "merge" to "pull", and it wouldn't really change ANYTHING. You'd still have to learn the new model. Linus -
> I claim that those "annoying little issues" are totally made up by > people > who had trouble wrapping their minds about git, and then make up > reasons > that have nothing to do with reality for why that might be so. Let me put this more personally: I continue to be bitten by stupid naming issues, and the myriad of little mostly non-orthogonal commands. My head is doing just fine otherwise, and has no problems wrapping it around the core of GIT. I've also used Darcs for almost a year. Darcs, which is much less overwhelming. This is not about CVS or SVN, so don't put them up as a strawman. If you want to argue that my brain is warped, use other distributed VCs as an example. The following mkdir x y cd x hg init echo hoi > bla hg add hg commit -m 'yes, I am also too stupid to refuse explicit empty commit messages' cd ../y hg init hg pull ../x pretty much works the same in Darcs, bzr and mercurial. With GIT, this is what happens [hanwen@haring y]$ git pull ../x fatal: Needed a single revision Pulling into a black hole? [hanwen@haring y]$ git fetch ../x warning: no common commits remote: Generating pack... Done counting 3 objects. Deltifying 3 objects. 100% (3/3) done Total 3, wremote: ritten 3 (delta 0), reused 0 (delta 0) Unpacking 3 objects 100% (3/3) done [hanwen@haring y]$ git checkout fatal: ambiguous argument 'HEAD': unknown revision or path not in the working tree. Use '--' to separate paths from revisions fatal: Not a valid object name HEAD [hanwen@haring y]$ git branch master fatal: Needed a single revision at this point, I resort to adding a bogus commit and/or editing .git/HEAD by hand. I'm sure there is a saner way of doing it, but I still haven't found out what it is. This might not be typical GIT use, but it does show the typical GIT user experience, at least mine. If you want to have another example of how not to design a I don't want ANYTHING to really change, I just ...
Han-Wen Nienhuys <hanwen@xs4all.nl> writes:
You asked it to fetch from the neighbour repository and merge it
into your current branch which does not exist (I presume that
you omitted to describe what you did in directory y/ and I am
assuming you did "mkdir y && cd y && git initdb" and nothing
You fetched without telling it in which tracking branch to store
what you fetched, and as a result your HEAD is not updated, so
your current branch still does not exist. A failure from
checking out nothingness is not an interface issue; expectation
You are not at any commit yet and you try to create a branch?
Of course, the "right" (in some sense of the word) thing is to
do "git clone x y" in the parent directory, without creating y
upfront.
If you have an empty y to begin with, then you can do this:
$ git fetch ../x :origin
$ git reset --hard origin
which would mirror a part of what "git clone" would have done
for you. It copies from the other repository, stores the tip in
your tracking branch called "origin", and make your HEAD to be
the same as origin. After these two commands, you would have
two branches, origin and master, and you will be on master.
You can name 'origin' any way you want. You might want to name
it 'x' to make it clear (to yourself) that it is used to track
what will happen in the neighboring repository 'x'. Also, you
would most likely be fetching and merging from the same ../x
from now on, so it might be handy to set up the remotes for it:
$ cat >.git/remotes/x <<EOF
URL: ../x
Pull: master:origin
EOF
Then subsequent work of yours would be done on 'master' branch
(you have only two branches, and origin is a tracking branch so
you will never make commits on it, which means the above is a
logical consequence), and from time to time you would sync with
whoever is working in ../x
$ git pull x
Here, 'x' is just a shorthand which looks up the URL: and Pull: line
through .git/remotes/x. If your .git/remotes/ ...Having said all that, I happen to think that this particular case of pulling into void could deserve to be special cased to pretend it is a fast forward (after all, nothingness is an ancestor of anything), if only to make new people's first experience more pleasant. Working from nothingness is something not usually done in everyday work, so from practical and technical point of view it does not add much _real_ value to the people who actually uses the system, but nevertheless, new people typically start learning the system from either cloned repository (which I believe is covered by the existing tools fairly well) or emptiness (which bitten us here in a bad way), and making the first experience more pleasnt to new people have a positive value of flattening the learning curve. So please consider that this is classified as a bug. -
If you make pushing into an empty repository work also, you fix the case of "create an empty repo for somebody, let them fill it up remotely later". Thanks! -- Dr. Horst H. von Brand User #22616 counter.li.org Departamento de Informatica Fono: +56 32 2654431 Universidad Tecnica Federico Santa Maria +56 32 2654239 Casilla 110-V, Valparaiso, Chile Fax: +56 32 2797513 -
This seems to work just fine now. I do it all of the time. -- Shawn. -
>> I don't want ANYTHING to really change, I just want a sane interface >> to it. > > I agree that you do not want to change anything. You just > needed a bit of handholding, because you deviated from the > cookbook usage, to correct your course. Users (well, I do at least) start fiddling with systems to find out how they work. Reading the manual is usually done as a last resort. I think this is pretty well documented in usability research. I'm trying to show how GIT is badly suited to this. Your response is to explain to me what I should have done. That's nice, but that approach doesn't scale, because you don't reach the dozens of users out there who try the same, fail and give up. If you really want to find out the weaknesses, you'd have to sit someone new to git in front of a computer, and let him figure how to operate it, while videotaping everything. Writing a manual for newbies is also an effective (and simpler and cheaper) approach of figuring out what needs to be changed. As another example: annoyances regarding program invocation - option handling: -x -f -z != -xfz , "--max-count 1" doesn't work, but needs an '=' - git --help lists an unordered set, which is too long scan quickly. I'd expect that list to either contain everything or the minimum set for daily use. I.e. the set introduced in a first tutorial. Why are merge, prune, verify-tag there? Try "bzr help" for comparison. - --pretty option with wholly uninformative options full, medium, short, raw. It's not even documented what each option does. I can go on with listing idiosyncrasies, but my point is not to get help as you remark in the other reply, there is IMO no reason for not having an empty 'master' branch. If master + HEAD gets created on the first commit, it might as well be created on the init-db. -- Han-Wen Nienhuys - hanwen@xs4all.nl - http://www.xs4all.nl/~hanwen -
oh, and another annoying one: git's insistence on firing up a pager if there is nothing to page, eg. try git-log je-n-existe-pas -- Han-Wen Nienhuys - hanwen@xs4all.nl - http://www.xs4all.nl/~hanwen -
Your example has nothing at all to do with "pull" vs "fetch", though. Your example is about something totally _different_, namely that under Bzzt. This is where you went wrong, and you blamed "pull". The way you do this in git is to NOT do "git init". Instead, you replace all the mkdir y cd ../y hg init hg pull ../x with a simple git clone x y and YOU ARE DONE. Now, we could certainly _make_ "git pull" work on an empty git project, but that has _nothing_ to do with what people have been talking about. In fact, the fact that "git fetch" kind of works is not exactly accidental (because "git fetch" _is_ meant to add new local branches too), but all the problems you have with it are due to the SAME issue. You started without any branch at all, because you started with an empty git repo, and you're simply not _supposed_ to do that. So current rule (and this is not new, it's always been true): the ONLY time you use "git init-db" is when you are going to start a totally new project. Never _ever_ otherwise. If you want to track another project, use It's not that it isn't typical, it's that you are using the wrong model. Maybe it's not well documented, I can easily give you that, but ALL your problems come from that fundamental starting point: you shouldn't have used "git init-db" in the first place. Somebody want to document it? Alternatively, we certainly _could_ make "git pull" just accept an empty git repo, and make it basically create the current branch. The sane interface _exists_. It's called "git clone". Linus -
Actually, only a 2 weeks ago, you suggested that I share the website and main source code for my project in a single repository for reasons of organization. In this setup I find it logical to do git init-db git pull ..url.. website/master to wind up with just the 5mb website, instead of the complete 70mb Yes, I would like that. -- Han-Wen Nienhuys - hanwen@xs4all.nl - http://www.xs4all.nl/~hanwen -
I don't disagree per se. It should be easy to support, it's just that it's not traditionally been something we've ever done. So the way you'd normally set up a single repo that contains multiple other existing repositories is to basically start with one ("git clone") and then add the other branches and "git fetch" them. So again, instead of "git init-db" + "git pull", you'd just use "git clone" instead. Note that there _is_ another difference between "git pull" and "fetch+merge". The difference being that "git pull" implicitly does the checkout for you (I say "implicitly", because that's the way the git merge conceptually works: we always merge in the working tree. That's not the only way it _could_ be done, though - for trivial merges, we could do them without any working tree at all, but we don't suppotr that). And that "git pull" semantic actually means that if you want a _bare_ repository, I think "git --bare init-db" + "git --bare fetch" actually does exactly the right thing right now too. But "git pull" would not be the right thing to use. Btw, another normal way to generate a central "multi-headed repo" for is to not use "pull" or "fetch" or "clone" at ALL, but I would likely do something like mkdir central-repo cd central-repo git --bare init-db and that's it. You now have a central repository, and you _never_ touch it again in the central place except to repack it and do other "maintenance" (eg pruning, fsck, whatever). Instead, from the _outside_, you'd probably just do git push central-repo mybranch:refs/heads/central-branch-name (actually, you'd probably set up that branch-name translation of "mybranch:refs/heads/central-branch-name" in your remote description, but I'm writing it out in full as an example). So there are many ways to do it. It just happens that "git init-db" followed by "git pull" is not one of them ;) (And the real reason for that is simple: "git pull" simply wants to have something to _start_ ...
You're misunderstanding me: the multi-repo is at git.sv.gnu.org is the remote one. The example I gave was about locally creating a single project repo from a remote multiproject repo. On a tangent: why is there no reverse-clone? I have no shell access to the machine, so when I created the remote repo, I had to push, and ended up putting 1.2 Gb data on the server. <looks at manpage> is this send-pack? From UI perspective it would be nice if this could also be done with clone, yes, this works. Two remarks: * it needs website/master:master otherwise you still don't have a branch. * why are objects downloaded twice? If I do git --bare fetch git://git.sv.gnu.org/lilypond.git web/master it downloads stuff, but I don't get a branch. If I then do git --bare fetch git://git.sv.gnu.org/lilypond.git web/master:master it downloads the same stuff again. -- Han-Wen Nienhuys - hanwen@xs4all.nl - http://www.xs4all.nl/~hanwen -
Ahh.
Ok, try the patch I just sent out, and see if it works for you. It
_should_ allow you to do exactly that
mkdir new-repo
cd new-repo
git init-db
git pull <remote> <onehead>
and now your "master" branch should be initialized to "onehead".
Oh, except I just realized that I forgot to do a "git checkout" in my
patch, so you'd need to add that (or do it by hand, but you really
shouldn't need to, since the checkout is implied by the "pull").
The downside with this is that it does NOT populate your "remotes"
information (like "git clone" would have done), so either we'd need to
teach "git pull" to do that too, or you just have to do it by hand (so
Yeah, you're supposed to "init-db" and "push". Right now, that tends to
unpack everything (which is bad), although that is hopefully getting fixed
"git push" uses send-pack internally, you shouldn't ever need to use it
The creation of a new archive tends to need special rights (with _real_
ssh access and a shell you could do it, but "ssh+git" really means "git
protocol over a connection that was opened with ssh, but doesn't
necessarily have a real shell at the other end").
So for most protocols, you simply cannot (and shouldn't) do it. Think
about services like the one that Pasky has set up, that allow you to set
up a new git repo - the setup phase really _has_ to be separate (because
you need to set up your keys etc).
So I think the above syntax is actually not a good one, because it cannot
work in the general case. It's much better to get used to setting up a
repo first, and then pushing into it, and just accepting that it's a
two-phase thing.
Also, from a bandwidth standpoint, you can often (although obviously not
always) make the setup start with something that is _closer_ to what you
want to do. So, for example, you'd often do something like:
(a) ssh to central repository
(b) create the new repository by cloning it _locally_ at the central
place from some other ...Btw, the magic heads are probably not all that well documented. They do come up in the man-pages, but I don't think there is any central place talking about them. We have: - "HEAD" itself, which is obviously the default pointer for a lot of operations, and that specifies the current branch (ie it should currently always be a symref, although we've talked about relaxing that) - "ORIG_HEAD" is very useful indeed, and it's the head _before_ a merge (or some other operations, like "git rebase" and "git reset": think of it as a "original head before we did some uncontrolled operation where we otherwise can't use HEAD^ or similar") I use "gitk ORIG_HEAD.." a lot, and if I don't like something I see when I do it, I end up doing "git reset --hard ORIG_HEAD" to undo a pull I've done. This is important exactly because ORIG_HEAD is _not_ the same as the first parent of a merge, since a merge could have been just a fast-forward. - "FETCH_HEAD" as mentioned. Normally you'd only use this in scripting, I suspect, but it's potentially useful if you prefer to do a fetch first and then check out it (perhaps cherry-picking stuff instead of merging, for example). So you could do (for example) git fetch some-other-repo branch gitk ..FETCH_HEAD git cherry-pick <some-particular-commit-you-picked> - "MERGE_HEAD" is kind of the opposite of "ORIG_HEAD" when you're in the middle of a merge: it's the "other" branch that you're merging. It's mainly useful for merge resolution, ie git log -p HEAD...MERGE_HEAD -- some/file/with/conflicts is a great way to see what happened along both branches (note the _triple_ dot: it's a symmetric difference), to see _why_ the confict happened. Most of the above are used implicitly in various cases, not just HEAD. The "--merge" flag to git-rev-list (and thus git log and friends) is just shorthand for the above "HEAD...MERGE_HEAD" behaviour (with the addition ...
Although if you have reflog enabled on your current branch there
is a 1 character shorter syntax:
gitk HEAD@{1}..
as recent Git understands that to mean the value that HEAD just had,
which is also what is in ORIG_HEAD. Except that unlike ORIG_HEAD
it can also show even older values (e.g. HEAD@{3}, 3 ops back)
and it works very, very well on tracking branches. "What did I
just fetch in next?" `git log next@{1}..next`
--
Shawn.
-
Heh. With a finnish keyboard, that "@" is AltGr+'2', and the '{'/'}' is
AltGr+'7'/'0', I guarantee that it's not "1 character shorter", it's
"three pretty complicated characters longer" and "off the normal path
where you hold your fingers on the keyboard ;)
And that's not even mentioning that '{'/'}' is a magic sequence for
filename expansion to the shell, so every time I see that, I have to think
about it (and it turns out that because there is no comma in between
there, it's ok. Otherwise you would need to quote it or escape them...)
So the reflog syntax is fine, but it's definitely not a "simple" syntax.
I'd only use it for things where I want something that ORIG_HEAD won't
give me ("ORIG_HEAD" you can type by just holding the shift key down all
the time, and letting your fingers dance over the keyboard, both on a US
and a Finnish keyboard).
And yes, I actually use a Finnish keyboard, still. Don't ask me why. I
don't actually need the It's not even all that convenient on a U.S. keyboard. My pinky suffers
a bit having to pop on and off of shift for the '{', '1', '}'. Then
again, I don't like having to hold shift down for all of ORIG_HEAD
either, (but it's definitely easier in comparison).
But since reflog does everything ORIG_HEAD does and more, shall we
just clean up the syntax somehow? Ideas anyone? And then fix the
documentation to explain that?
-Carl
I forgot that you use a finnish keyboard. :-) I agree with you; its not easier to type, for you. Me, I'm a dumb American who uses a Kinesis keyboard, therefore my left foot is my shift key and its in sync with my fingers. I have no extra pinky load for either syntax. And since the reflog syntax works in a lot more contexts (e.g. after a fetch into a tracking branch) I have just forgotten about ORIG_HEAD entirely. Oh sure, I know its there, but its not something I think about using... -- Shawn. -
Yes, this was my exact thought when reading what Linus wrote. ORIG_HEAD might be fine and all, but it pales in functionality compared to what reflog provides. I would very much like to see reflog getting first-class citizen support in git: 1. Be on by default 2. Get documented in all the right places, (much better than adding documentation for ORIG_HEAD in my opinion) 3. Tighter integration with branch manipulations. Do we already delete reflog when deleting a branch? We don't have a branch rename operation, but if we get one, renaming the reflog should go hand-in-hand, etc. -Carl
I have: git repo-config --global core.logAllRefUpdates true especially since Junio fixed it to only create logs for heads and not tags. That way its on by default for me. But I think it should Agreed. I'm not likely to do it anytime soon however, so I'm hoping Yes, we delete the log when we delete the branch, and we prune back the empty directories too just like we do on the branch side, so that new branches can be correctly created. There was a recent discussion about that from Junio if I recall. Several people that I work with have asked that branch rename support be added to Git, and that if you rename the branch the reflog follows. Because in their mind they are simply changing the name of the branch, any old history of that branch should stick around. I tried to think of an option to "git branch" to do the rename but kept thinking that: git rename-branch old new is the better syntax... even though that's command number 133 or something like that... We should stick a "null" event into the reflog during a branch rename. Make both the old and new SHA1 the current SHA1 but drop a message in saying "renamed branch old -> new" (for example). -- Shawn. -
Why is it not useful for tags for having logs? I also have a question: Does git-fsck-objects/prune check the ref logs? Mark -
When I make a tag that says "this is the v1.2.0 release", it is expected it won't change in the future, ever. I _can_ make mistake and tag a wrong commit under v1.2.0 name, in which case I may have to replace it with another corrected tag, but recoding that mistake does not really add value. So most of the time ref-log for a tag would contain only one entry per file, its creation, but that creation time is already recorded in the tag object itself anyway. At times, it may be useful to have some floating tag that point at the "latest", or "today's", but that use is a minority. For these minority cases, you can manually create an empty file under .git/logs/ directory to record their updates. The configuration mechanism only kicks in when there is no such existing file to prime the process, and not creating ref-log for They deliberately ignore ref-log for the same reason lost-found does not drop found refs under .git/refs hierarchy. This only matters if you somehow rewind an existing branch in order to lose part of its history, using "reset --hard HEAD~n" or "rebase". If the updates to your branch tips always build on top of the previous (either by commiting on top of the current, merging on top of the current, or fast-forwarding), and if you never rewind the branch, the commits recorded in the ref-log for the branch are always ancestors of the tip of the branch, so checking ref-log does not give you anything other than slowing the operation down. However, if you rewind the tip of a branch, the story changes. Until the next "prune", objects reachable from the ref-log of the branch but not reachable from the tip of the branch are still available in your object store and in a pinch you can recover them, but after a "prune" they will be lost forever if they do not have any other references. So it might seem that they should be protected from pruning. But if you did so, you can never remove cruft from your object store once you make a mistake. You can clean up ...
Are you sure about this? I've seen "next@{1}" to look at
history of the named branch, but never history of "HEAD".
-
Yes. :-) If the ref name is a symref then we resolve the symref all the way down to the real ref before we open and walk the reflog. Therefore this works. -- Shawn. -
True, except if you did:
$ git pull
$ git checkout otherbranch
$ git show HEAD@{1}
My real point was that I was wondering if it also makes sense
for ref-log to record switching branches for the symref itself.
But after sending that message I thought about it a bit more and
concluded that it is not an interesting information. It is more
code that affects unrelated places even if we were to implement
it and without real gain, so let's not log symref itself and
keep the current implementation.
-
I agree completely. I have no interest in a history of what branches I've recently been on. All I care about is the history of this branch. And I consider HEAD to be nothing but a shortcut that always points to the current branch... so its darn useful for that. In retrospect CURR may have been a better name for the HEAD symref but its far too late to even consider changing that, so lets not go down that road. :-) -- Shawn. -
Hi, This is actually a perfect example for - a script that is porcelain as well as plumbing (you are supposed to use it directly, or via pull), and for - a terrible UI. _If_ you use git-fetch directly you virtually always want to store the result. I was tempted quite often to submit a patch which adds a command line switch --no-warn, which is passed to git-fetch by git-pull, and without which git-fetch complains if the branch-to-be-fetched is not stored right away (and refuses to go along). _Also_, git-pull not storing the fetched branches at least temporarily often annoyed me: the pull did not work, and the SHA1 was so far away I could not even scroll to it. The result: I had to pull (and fetch!) the whole darned objects again. Again, I was tempted quite often to submit a patch which makes git-pull fetch the branches into refs/fetch-temp/* and only throw them away when the merge succeeded. Ciao, Dscho -
Hi, I am not sure that documenting FETCH_HEAD better would help. As Han-Wen pointed out (and some colleagues of mine who would never subscribe to a mailing list), people do not read the manual, but rather try to wrap their heads around the inner workings from the interface. And FETCH_HEAD just does not meet _any_ expectation a sane (read: untainted) user might have. While I'm at it: the problem I pointed out with -pull may annoy just me. But there is another problem with "git fetch": a common work flow is tracking other peoples branches. And since git makes it so easy to have multiple branches, chances are that you track more than one branch per remote repository. Now, an old gripe of mine was the lack of "git fetch --all". I wrote a script for that (Linus would be proud of me!), which just does "git ls-remote" and constructs a command line for "git fetch" from that. But even if you agree with the common story that you should specify the branches you want to track: it is hard! If I were new to git, after reading some tutorials I would _expect_ "git fetch" to be the tool to track branches. (I posted a patch to at least be able to store the current "git fetch" command line under a nick IIRC). But it does not. (Of course, after reading several documentation, as a new user I would eventually find that I should edit .git/remotes/<nick>, or even edit/-repo-config the remotes information in the config, but I would fully expect a new user to give up before reaching that stage.) But maybe I got it all wrong and this is not the common expectation... Ciao, Dscho -
Again, why didn't you use FETCH_HEAD? If the user doesn't give us a head to write to, we clearly MUST NOT write to any long-term branch. That would be a _horrible_ mistake. So all your complaints seem totally misplaced. The UI is both usable and practical, and your complaint that git pull doesn't store the fetched branches is just NOT TRUE. And your "solution" is obviously totally unusable. git ABSOLUTELY MUST NOT overwrite any existing branches unless explicitly told to do so by the user. So I really don't see your point. A lot of the complaints seem to not be about the interfaces, but about people not _understanding_ and knowing what the interfaces do. If you were confused about something (like not realizing that FETCH_HEAD is there and very much usable), how about sending in a patch to make FETCH_HEAD use clearer in whatever docs you looked at and didn't find it mentioned in. Now, there is no question that some of the interfaces can get a bit "interesting" to use. For example, if you really don't want to re-fetch for some reason, FETCH_HEAD actually does contain enough information that you should be able to just re-do a failed merge, for example, including the message generation. But at that point it really _does_ get a bit complicated, and you end up doing something like git merge "$(git fmt-merge-msg < .git/FETCH_HEAD)" HEAD FETCH_HEAD which should _work_, but I'm not going to claim that it's all that easy to understand. (That said, read that one-liner a few times, and suddenly it doesn't seem _that_ complicated any more, now does it? You can probably even guess what it's really going to do, even if you don't know git all that well. It's not unreadable line noise, is it?) Of course, if I had a merge that failed (the most common reason being that I had some uncommitted patch in a file that wanted to be updated by the merge), I'd never actually do the above one-liner. I'd just re-do the pull. But if networking was _really_ ...
Btw, I'd like to claim that this is a _great_ user interface. Yeah, it's different from other SCM's. I don't think you'd really want to script a merge like this in CVS, especially not using standard UNIX pipelines etc. But it's an example of how a lot of git operations - even the "high level ones" are pretty scriptable, using very basic and very simple standard UNIX shell scripting. So even though I'd not actually _do_ the above one-liner, I think it's a great example of how git really works, and how scriptable it can be, without a lot of huge problems. So considering that "FETCH_HEAD" works pretty much everywhere, and that you can also use the totally non-scripting approach of doing "standard" SCM things like git diff ..FETCH_HEAD or gitk HEAD...FETCH_HEAD to look at what got fetched (and in the latter case look at both the current HEAD _and_ FETCH_HEAD, and what was in one but not the other), I really think it's unfair to say that "git fetch" does not have a nice UI. It's just that "git fetch" can be used two totally different ways: - "git fetch" to get something temporary: use FETCH_HEAD, and do _not_ specify a destination branch - "git fetch" as a way to update the branches you already have, by either using explicit branch specifiers (which would be unusual, but works), or by just having the branch relationships listed in your .git/remotes/ file or .git/config file. both are actually very natural things to do. What is probably _not_ that natural is to do the explicit branch specifier, ie git fetch somerepo remotebranch:localbranch which obviously works, but you wouldn't want to actually do this very often. Either you do something once (and use FETCH_HEAD, which is actually nicer than a real branch in some respects: it also tells you were you fetched _from_, and it can contain data on merging from _multiple_ branches), or you set up a "real translation" in your configuration files. So I would say that ...
Hi, It is a terrible UI, because it was not that obvious to me. And I consider myself not a git newbie. Besides, it is not really a temporary branch. If it was, the pull would I was _not_ suggesting a long-term branch. Just a way to do-what-i-want Guess three times why I did not post the patches. But the real problem is not necessarily the behaviour; it is the obscure fashion of the behaviour. You may not understand that problem, because you were there from the beginning. You saw the big-bang and how all the quarks formed all of a sudden, and how matter and eventually planets and suns came into being. But others (me included) were not there. Or they did not really watch. And now they see all these creatures, and plants, and bacteria, and they do not understand how these are all connected, because of that. And now they think "wow that must have been some intelligent design, and really a miracle, and I cannot understand how it works." But that is not true (the latter part of course). There is something to be said about the simplicity of Mercurial. It's inner workings may suck, but people get easily attracted by it. I do not claim we should imitate Mercurial, or even hide the index (even if I sometimes wonder if the index is not just a clever way to accelerate But the interfaces should be usable interfaces! They should _explain_ what I find that quite easy to understand. Why? Because I happen to _know_ the syntax of -merge and -fmt-merge-msg. For similar reasons I _understand_ why -pull behaves like it does. But others don't; they will shudder and then run. Maybe it is not important that -pull fetches all objects all over again. But it _is_ important to make things like merging branches (local or remote) trivial. It _is_ important to make the user experience be fun. Ciao, Dscho -
Heh. The "temporary branches" are actually the _original_ branches as far as git is concerned. The long-term branches only came later. So in many ways, HEAD, FETCH_HEAD, MERGE_HEAD and ORIG_HEAD are more fundamental than any long-term branch has ever been, and maybe they should be taught first as such. So you're newbie enough that you've only seen those new-fangled "real" branches. When I was young, we had to walk to school up-hill in three feet of snow Well, exactly because they are temporary, we can't actually trust the objects they point to. They have no "real" long-term life, so no, I'm afraid that we always will have to re-fetch the objects, because fetching them is the only way to know that we still have them. That said, we could certainly _make_ them be honored by things like "git prune" and friends. But yes, they really _are_ temporary branches right now, and part of the meaning of that "temporary" is exactly the fact that git fetch will not trust that you still have the objects. For example, if you used one of the old-fashioned commit walkers, maybe we got the initial commit, but we may not have gotten the whole _chain_. See? Well, we clearly should document them better. Anybody? Linus -
Older in git's history as it developed is not a good match for more I for one am totally unsatisfied with this approach. Here's an operations I'd like to be able to do: Given a (URL, branch) pair I'd like I'd like to be able to investigate that code, (say with the fancy new "read-only branch" concept we've been talking about). What are my options for this operation? What might a new user's reaction to them be? a) git fetch URL branch git checkout FETCH_HEAD This is really ugly. A name like "FETCH_HEAD" is something a user should really never have to type. It's hideously hard to type and has no natural discoverability. Yuck, yuck, yuck. b) vi .git/remotes/something git fetch something git checkout branch Also yuck. I hope it's obvious that having to edit a configuration for this simple operation is a non-starter. c) git fetch URL branch:local-branch git checkout local-branch We're getting close to the desired functionality now, but the UI makes users cringe? "What's that : for?" Why do I need another name?" etc. Linus, you yourself said this is a form that users should generally avoid. d) git fetch URL branch:branch git checkout branch One step closer. But there's still that goofy extra ':' and a doubled name in the first command. "Why is that there? Git sure is weird...". What I think this operation should look like is: git fetch URL branch git checkout branch And the fetch should just complain if there's a name clash. Or better, the fetch should tuck the fetched branch into its own URL-specific namespace and then the checkout command can kindly prompt if there is any ambiguity: Which "branch" do you want? local/branch remote-url/branch or whatever. See? That's what reasonable UI should look like. Please feel free to keep using vestiges like FETCH_HEAD as much as you like, but please don't recommend documenting them better as a solution for UI warts in git. (If you ...
Hi, Nonono. We made _sure_ that FETCH_HEAD is only written once _all_ the objects were received. So, actually, we _can_, and we _should_ trust the objects they point to! Huh? I am quite certain that FETCH_HEAD is not updated in that case. If it is, that's a bug. Ciao, Dscho -
It may be updated and then things may break _afterwards_. git-prune will happily blow anything referenced by FETCH_HEAD, it's not considered by the fsck-objects reachability analysis. -- Petr "Pasky" Baudis Stuff: http://pasky.or.cz/ #!/bin/perl -sp0777i<X+d*lMLa^*lN%0]dsXx++lMlN/dsM0<j]dsj $/=unpack('H*',$_);$_=`echo 16dio\U$k"SK$/SM$n\EsN0p[lN*1 lK[d2%Sa2/d0$^Ixp"|dc`;s/\W//g;$_=pack('H*',/((..)*)$/) -
Hi, This actually underlines my point: FETCH_HEAD is no _real_ branch, not even a temporary one. If it was, git-prune would not lose the related objects. Ciao, Dscho -
From the point of view of a user, there is not really a difference between the two. As a user, you form a mental model of how things work by looking at the interface. If the interface is bad, the user creates a faulty model in his head, and starts doing things that are perfectly logical in the faulty model, but stupid and silly when you consider the actual internals. A nice book about this is "The Design of Everyday Things" by Donald Norman. -- Han-Wen Nienhuys - hanwen@xs4all.nl - http://www.xs4all.nl/~hanwen -
What happens on savannah is that the sysadmins set up an empty GIT repo with access, and leave it to you to push the stuff. Of course, Perhaps ; from a UI viewpoint, it would be nice though, even if it were aliased to a simple push. (Darcs has a get command analogous to No, I don't understand. In the fetch all the objects with their SHA1s were already downloaded. I'd expect that the fetch with a refspec would simply write a HEAD and a refs/heads/master, and notice that all the actual data was already downloaded, and doesn't download it again. -- Han-Wen Nienhuys - hanwen@xs4all.nl - http://www.xs4all.nl/~hanwen -
Here's a very lightly tested patch that allows you to use "git pull" to populate an empty repository. I'm not at all sure this is necessarily the nicest way to do it, but it's fairly straightforward. Junio, what do you think? Linus --- diff --git a/git-pull.sh b/git-pull.sh index ed04e7d..7e5cee2 100755 --- a/git-pull.sh +++ b/git-pull.sh @@ -44,10 +44,10 @@ do shift done -orig_head=$(git-rev-parse --verify HEAD) || die "Pulling into a black hole?" +orig_head=$(git-rev-parse --verify HEAD 2> /dev/null) git-fetch --update-head-ok --reflog-action=pull "$@" || exit 1 -curr_head=$(git-rev-parse --verify HEAD) +curr_head=$(git-rev-parse --verify HEAD 2> /dev/null) if test "$curr_head" != "$orig_head" then # The fetch involved updating the current branch. @@ -80,6 +80,11 @@ case "$merge_head" in exit 0 ;; ?*' '?*) + if test -z "$orig_head" + then + echo >&2 "Cannot merge multiple branches into empty head" + exit 1 + fi var=`git-repo-config --get pull.octopus` if test -n "$var" then @@ -95,6 +100,12 @@ case "$merge_head" in ;; esac +if test -z "$orig_head" +then + git-update-ref -m "initial pull" HEAD $merge_head "" || exit 1 + exit +fi + case "$strategy_args" in '') strategy_args=$strategy_default_args -
Yeah, I talked about making "merge" treat missing HEAD as a special case of fast forward, but I like yours better. It is a lot cleaner and to the point. -
So this is the place that probably wants a "git-checkout" before the exit, otherwise you'd (illogically) have to do it by hand for that particular case. Of course, we should _not_ do it if the "--bare" flag has been set, so you migth want to tweak the exact logic here. Linus -
As you said, pull inherently involve a merge which implies the existence of associated working tree, so I do not think there is any room for --bare to get in the picture. We already do the checkout when we recover from a fetch that is used incorrectly and updated the current branch head underneath us. To give the list a summary of the discussion so far, here is a consolidated patch. -- >8 -- From: Linus Torvalds <torvalds@osdl.org> Subject: git-pull: allow pulling into an empty repository We used to complain that we cannot merge anything we fetched with a local branch that does not exist yet. Just treat the case as a natural extension of fast forwarding and make the local branch'es tip point at the same commit we just fetched. After all an empty repository without an initial commit is an ancestor of any commit. Signed-off-by: Junio C Hamano <junkio@cox.net> --- diff --git a/git-pull.sh b/git-pull.sh index ed04e7d..e23beb6 100755 --- a/git-pull.sh +++ b/git-pull.sh @@ -44,10 +44,10 @@ do shift done -orig_head=$(git-rev-parse --verify HEAD) || die "Pulling into a black hole?" +orig_head=$(git-rev-parse --verify HEAD 2>/dev/null) git-fetch --update-head-ok --reflog-action=pull "$@" || exit 1 -curr_head=$(git-rev-parse --verify HEAD) +curr_head=$(git-rev-parse --verify HEAD 2>/dev/null) if test "$curr_head" != "$orig_head" then # The fetch involved updating the current branch. @@ -80,6 +80,11 @@ case "$merge_head" in exit 0 ;; ?*' '?*) + if test -z "$orig_head" + then + echo >&2 "Cannot merge multiple branches into empty head" + exit 1 + fi var=`git-repo-config --get pull.octopus` if test -n "$var" then @@ -95,6 +100,13 @@ case "$merge_head" in ;; esac +if test -z "$orig_head" +then + git-update-ref -m "initial pull" HEAD $merge_head "" && + git-read-tree --reset -u HEAD || exit 1 + exit +fi + case "$strategy_args" in '') strategy_args=$strategy_default_args -
Fair enough. Feel free to add the signed-off-by from me too, Linus -
For that we'd also need a way for clone to be able to fetch just a
single branch, and not all of them as well.
There is some clone vs. fetch asymmetry here that has annoyed me for a
while, and that I don't think has been mentioned in this thread
yet. Namely:
clone: can only be executed once, fetches all branches, "remembers"
URLs for later simplified use
fetch: can be executed many times, fetches only named branches,
doesn't remember anything for later
I've often been in the situation where I cloned a long time ago, but
I'd like to be able to fetch everything that I would get if I were to
start a fresh clone.
-Carl
Hi, Never ever underestimate pet peeves. If we give many people an obvious reason (however trivial and bike-shed-coloured) to complain, they will complain. If we pull (pun intended) that reason away under their collective backsides, they will have to find another reason to complain. But by the time they found something, they will already be happy git users! But since you just provided a patch to make life easier on non-gitters, I guess you agree with that already. And hopefully you also agree that enhancing the syntax of git-merge to grok "git-merge [-m message] <branch>" and "git-merge [-m message] <url-or-remote> <branch>" would be a lovely thing, luring even more people into using git. Maybe they even start complaining about subversion and CVS calling a merge "update", who knows? Ciao, Dscho -
I do actually think that this discussion has been informative, partly because I never even realized that some people would ever think to do "init-db" + "pull". Making things like that work is easy enough, it's just that I never saw any point until people complained. And when they complained, the initial complaint wasn't actually obvious. Only when Han-Wen actually gave something that didn't work, was it clear that the real issue wasn't so I definitely think we can make "git merge" have a more pleasant syntax. I'm just still not sure that people should actually use it ;) My real point was/is that usually it's really not the "naming details" that people _really_ have problems with. The real problems tend to be in learning a new workflow. We can make some of those workflows easier, but I would heartily recommend that people not worry about naming of "pull" vs "fetch", because that's almost certainly not really the issue. Instead, if you have a problem, rather than concentrating on the names of the programs, say: - what do you want to get done. Most likely it's _trivial_ to do with git, it's just that somebody used the wrong approach, and then it didn't work at all. - give actual examples of a workflow that didn't work or was complex. (again, the "init-db" + "pull" example). And yes, in many cases, it might well be a case of "sure, we can make that _other_ workflow work too". But somebody like me, who has used git for a year and a half, and used BK before it, probably simply uses a different workflow than somebody who comes from CVS. For example, I suspect that your gripe with "git fetch" was just from using it in a really awkward manner. Maybe we could make your workflow work with git too, but maybe it really already (and always) did, you just used a particular tool in a way that made the use be really really painful. Sometimes it's just a question of "ok, use it like _this_, and now it's actually really ...
I agree that discussions on naming may cloud the issue, but "learning the workflow" implies that people should adapt to the limitations of their tools. That's only a viable stance when the tools are finished and completely perfect. Until that time, it would be good goal to remove all idiosyncrasies, all gratuitious asymetries and needless limitations in the commands of git, eg. - clone but not a put-clone, - pull = merge + fetch, but no command for merge + throw - clone for getting all branches of a repo, but no command for updating all branches of a repo. Of course, when all warts are fixed, backward compatibility will force us to choose some new names. At that point, a discussion on naming is in place. -- Han-Wen Nienhuys - hanwen@xs4all.nl - http://www.xs4all.nl/~hanwen -
This one I can understand, but how would you propose to "update all branches", in other words what's your design for mapping remote branch names to local branch namespaces? It would be nice if the design does not straightjacket different repository layouts different people seem to like, but I think it would be Ok to limit ourselves only to support the straight one-to-one mapping and support only separate-remote layout. -
put clone would be the putative inverse of clone, ie. make a clone of
throw is the hypothetical opposite of fetch. I agree that this is
academical, because it's logical to only allow fast-forwards for
I think the whole clone design is a bit broken, in that the "master"
branch gets renamed or copied to "origin", but all of the other
branches remain unchanged in their names.
It's more logical for clone to either
* leave all names unchanged
* put all remote branches into a subdirectory. This would also make
it easier to track branches from multiple servers.
At present, I have in my build-daemon the following branches,
cvs-head-repo.or.cz-lilypond.git
hanwen-repo.or.cz-lilypond.git
hwn-jcn-repo.or.cz-lilypond.git
lilypond_1_0-repo.or.cz-lilypond.git
lilypond_1_2-repo.or.cz-lilypond.git
lilypond_1_4-repo.or.cz-lilypond.git
lilypond_1_6-repo.or.cz-lilypond.git
lilypond_1_8-repo.or.cz-lilypond.git
lilypond_2_0-repo.or.cz-lilypond.git
lilypond_2_2-repo.or.cz-lilypond.git
lilypond_2_3_2b-repo.or.cz-lilypond.git
lilypond_2_3_5b-repo.or.cz-lilypond.git
lilypond_2_4-repo.or.cz-lilypond.git
lilypond_2_6-repo.or.cz-lilypond.git
lilypond_2_8-repo.or.cz-lilypond.git
master-git.sv.gnu.org-lilypond.git
master-hanwen
master-repo.or.cz-lilypond.git
origin-repo.or.cz-lilypond.git
stable
stable-2.10
stable--2.10-git.sv.gnu.org-lilypond.git
It would solve lots of problems for me if cloning and fetching would
put branches into a subdirectory, ie.
git clone git://repo.or.cz/lilypond.git
leads to branches
repo.or.cz/lilypond_2_8
repo.or.cz/lilypond_2_6
repo.or.cz/lilypond_2_4
repo.or.cz/master
(etc..)
--
Han-Wen Nienhuys - hanwen@xs4all.nl - http://www.xs4all.nl/~hanwen
-
So effectively to tell git push not to unpack on the remote side, and to push all branches and relevant tags. That's basically exactly what git clone --use-separate-remote should do. Now only if it would become the default... :-) -- Petr "Pasky" Baudis Stuff: http://pasky.or.cz/ #!/bin/perl -sp0777i<X+d*lMLa^*lN%0]dsXx++lMlN/dsM0<j]dsj $/=unpack('H*',$_);$_=`echo 16dio\U$k"SK$/SM$n\EsN0p[lN*1 lK[d2%Sa2/d0$^Ixp"|dc`;s/\W//g;$_=pack('H*',/((..)*)$/) -
As long as its consistent with "clone" I'll be happy, (I think as part of a separate topic we need to fix the mappings in clone, see --use-separate-remotes as default and related). The current case is really annoying where I have to throw use clone into a new repository just to get everything, rather than just being able to fetch everything into the repository I already have. -Carl
What I want here is a command "git update" that fetches and fast-forwards the all branches which are designated as "tracking" a branch in some known remote repository. And git-clone would setup all branches appropriately so that they would be updated by git-update. Additionally, it would be nice if git-update would also create new tracking branches for all remotes repositories that had been designated as being tracked, (and git-clone would do this as well). There should also be a mechanism to easily create new tracking support for specific branches or all branches of a repository, (could be "git fetch URL branch" or "git fetch --all URL", for example). With this kind of setup, I would use "git update" regularly, and only ever merge locally. And by definition merging with any local tracking branch would have just as much information available as "pull URL branch" so the message would be the same. I've been using git for 10-11 months, so I think I understand the models fairly well, and I'd be really happy with a setup like that. I also have talked with a fair number of (non-git-using) users who think git is confusing, but I think would find the above scenario just fine. In this scenario, git pull would still work just fine, but it would also be much easy to teach a workflow that didn't use pull at all, so if there's any git-pull confusion that's an actual problem, it could be avoided. Junio, what do you think of a setup something like that? I really don't want to create a command other than "git" to implement it. -Carl
As mentioned, in order to "put-clone", you generally have to "create" first, so the "put-clone" really makes no sense. The _true_ reverse is really your - "git init-db" on both sides - "git pull" (your workflow ;) on receiving - "git push" on sending. The fact that we can do "git clone" on the _receiving_ side is an assymmetry, but it's not gratutous: when receiving we don't need any extra permissions or setup to create a new archive. In contrast, when sending, Again, this is not gratuitous, and the reason is very similar: when you pull, you're pulling into something that _you_ control and _you_ have access to, namely your working directory. In order to merge you have to have the ability to fix up conflicts (whether automatically or manually), and this is something that you _fundamentally_ can only do when you own the repo space. Again, when you do "push", the reason you can't merge is not a "gratuitous assymmetry", but a _fundamental_ assymmetry: by definition, you're pushing to a _remote_ thing, and as such you can't merge, because you can't fix up any merge problems. See? In many ways, if you want _symmetry_, you need to make sure that the _cases_ are symmetrical. If you have ssh shell access, you can often do that, and the "reverse" of a "git pull" is actually just another "git pull" from the other side: ssh other-side "cd repo ; git pull back" Now they really _are_ symmetrical: "git pull" is really in many ways ITS OWN reverse operation. But "push" and "pull" _fundamentally_ aren't symmetric operations, and you simply cannot possibly make them symmetric. Any system that tries would be absolutely horrible to use, exactly because it would be either: - making local/remote operations totally equivalent This sounds like a "good" thing, but from a real user perspective it's actually horribly horribly bad. Knowing the difference between local and remote is what allows a lot of performance optimizations, and a ...
Point taken; thank you. In that case, we're full circle with the command naming issues. Push and pull are fundamentally asymmetric operations, but then a consistent UI would dictate that they wouldn't be named symmetrically, as they are now. -- Han-Wen Nienhuys - hanwen@xs4all.nl - http://www.xs4all.nl/~hanwen -
I think there's a fundamental assumption built into the design of git that most programmers accustomed to a corporate environment don't understand. Namely, that each programmer owns his or her entire "repository", and can do whatever he or she darn well pleases with it at any time. Go ahead and create hundreds of transient branches as part of a scripted "merge complexity metric" calculation. Try three different refactoring strategies on different branches, abandon two of them, and prune them months later. And generally use the power of the SCM to juggle a lot of things at once, because there's no sysadmin gatekeeper stopping you, and the thing is designed and coded scalably so it doesn't grind to a halt as soon as everyone has dozens of private branches. Even if you do find a way to push git in a direction that it doesn't scale, it's no one's problem but your own -- people who pull from you are pulling the _content_ on the branches they care about, not the structure of your repository. One person's gratuitous asymmetry is another's minimalism. (If the symmetric thing doesn't make any sense or can't be implemented scalably, leave it out.) It is more important that git continue to pull = fetch + merge. It is (almost?) always followed by a judgment call based on the merge results. merge + throw doesn't make any sense in terms of the job at hand, which is facilitating human judgments clone is shorthand for the steps involved in setting up a new repository with content similar to an existing one. There isn't any merge involved, and no scope for human judgment, so it's simplest to clone the whole state of the remote repository (including tags and branches) and let the user blow away any branches he doesn't need. But once the clone is done, all of those branches are _truly_ _local_ -- they don't retain any reference to the remote branches, and you can commit to all of them. The only entry placed in .git/remotes is the "origin" of the new clone, which is the ...
Actually, this "origin" entry does contain "Pull:" lines for all of the branches that were cloned, so that "git pull" fetches and merges updates to all of these branches. (If upstream is in the habit of reverting things, you may need "git pull -f"; I just did that on the git repo to handle a failure to fast-forward on the "pu" branch.) Presumably "git branch -D" should inspect everything under .git/remotes to see whether one or more Pull: lines need to be deleted along with the branch. Currently, it looks like "remotes" entries are created only by "git clone" or by hand. Junio, are there any plans to manage the contents of "remotes" through the tool instead of by hand? Cheers, - Michael -
I am not sure what you mean. .git/remotes files do not describe any relationship between local branches (and that is where one of the problem raised in recent thread -- pull does not notice on which branch you are on and change its behaviour depending on it), so I do not think there is anything gained for "git branch I muttered something in a near-by thread Message-ID: <7vr6w78b4x.fsf@assigned-by-dhcp.cox.net> I am reasonably sure a separate tool (what I tentatively called "maint-remote" in the message) is necessary, because, while it would be relatively easy to make "git fetch" and friends to add new mappings in the default way under a new option, people with different workflows would want differnt "default mappings", and adding new mappings for _all_ remote branches is useful only for people who work in one particular way (namely, the CVS-style "the central distribution point is where everybody meet" model). The tool, under "interactive" mode, would probably take one parameter, the short name of a remote ($name), and would give you a form to update its URL:, shows ls-remote output against that repository and would let you: - update the URL: which would probably cause the ls-remote to be re-run; - remove existing mappings; - add mappings for a remote branch for which you do not have a corresponding tracking branch, with a straightforward default mapping: refs/heads/$branch:refs/remotes/$name/$branch But I haven't thought things through yet. -
.git/remotes/foo does contain Pull: lines which indicate the local branch onto which to _fetch_ remote changes. It's the subsequent _merge_ that doesn't notice which branch you have checked out. Cheers, - Michael -
Han-Wen Nienhuys <hanwen@xs4all.nl> wrote: throw + merge (at the remote end, that is)? -- Dr. Horst H. von Brand User #22616 counter.li.org Departamento de Informatica Fono: +56 32 2654431 Universidad Tecnica Federico Santa Maria +56 32 2654239 Casilla 110-V, Valparaiso, Chile Fax: +56 32 2797513 -
Yes, "bk pull" had an implied merge. But, the reason why bk pull was never really a problem with Bitkeeper is because it didn't really have support for multiple branches active within the same repository --- what Larry called "lines of development". Or rather, Larry started down the path of implementing lines of development, and then never fully supported it, mainly because making it easy for people to use was the tricky part. So with Bitkeeper, with "bk pull" there was never any question about which branch ("line of development") you would be merging into after doing a "bk pull", since there was only one LOD, and given that BK had the rule that a within a LOD only one tip was allowed, a "bk pull" _had_ to do do a merge operation. The moment you start supporting multiple unmerged tips in a repository i.e., branches, it raises the question, "which branch should the pull operation merge onto"? And git's answer, "the current branch", is often not the right one. *That's* why always doing a merge isn't always the right answer, and so in the git world, people are told, use "git fetch" instead, and in the hg world, "hg pull" doesn't do the merge. IMO, it's a fundamental result of the fact that both git and hg have chosen to support mulitple LOD's, whereas BK punted on the concept. If you are operating on your local development branch, the reality is that merging is probably not the right answer in the general case, which is why the hg world have omitted doing the merge. And by telling people, use "git fetch" instead, that's also an implicit admission that merging onto the current branch is often not the Right Thing. The problem is that "pull" is a very evocative word, especially given the existence "push", and so in the git world we are reduced to telling people, "you really don't want to use pull, trust me". Is this a major issue? Not really; I can think of a number of other issues that make git hard to learn, and why hg has a more gentle learning curve, ...
I agree, but I wonder why you are pulling/fetching (with or without merge) if you are operating on your local development I would rather say "use 'git branch' to make sure if you are I have to disagree with this. In the simplest CVS-like central repository with single branch setup in which many "novice users" start out with, there is almost no need for "git fetch" nor tracking branch. You pull, resolve conflicts, attempt to push back, perhaps gets "oh, no fast forward somebody pushed first", pull again, then push back. So I am not sure where "you really do not want to use pull. trust me" comes from. It is a different story for people who _know_ git enough to know what is going on. They may be using multiple branches and interacting with multiple remote branches, and there are times you would want fetch and there are other times you would want pull. But for them, I do think the suggestion would never end with "trust me" -- they would understand what the differences are. -
We do that for Wine. The problem is that we recommend using git-rebase to make it easier for occasional developers to keep a clean history, and rebase and pull interfere badly. The result is that we recommend always using fetch+rebase to keep up to date, but this is confusing many people too, because git-fetch appears to do a lot of work yet leaves the working tree completely unchanged, and git-rebase doesn't do anything (since in most cases they don't have commits to rebase) but has an apparently magical side-effect of updating the working tree. Ideally it should be possible to have git-rebase do the right thing even if the branch has been merged into; then we could tell people to always use git-pull, and when they get confused by seeing merges in their history have them do a git-rebase to clean things up. -- Alexandre Julliard julliard@winehq.org -
How do those developers submit their changes? Do they push? If they do, git-rebase can be saving one merge at most, and the merge is actually a good thing (someone should write some nice standalone writeup about that). If they don't have push access and maintain their patches locally until they get accepted, perhaps it would be far simpler for them to use StGIT? -- Petr "Pasky" Baudis Stuff: http://pasky.or.cz/ #!/bin/perl -sp0777i<X+d*lMLa^*lN%0]dsXx++lMlN/dsM0<j]dsj $/=unpack('H*',$_);$_=`echo 16dio\U$k"SK$/SM$n\EsN0p[lN*1 lK[d2%Sa2/d0$^Ixp"|dc`;s/\W//g;$_=pack('H*',/((..)*)$/) -
For regular developers, sure. But regular developers will need to properly understand the git model anyway, and then they will able to make sense even of the standard git commands ;-) The problem is that there isn't a smooth progression to that point. At first, a user will simply want to download and build the code, and for that git-pull works great, it's a one-stop command to update their tree. Then after a while the user will fix a bug here and there, and at that point git-rebase is IMO the best tool, it's reasonably easy to use, doesn't require learning other commands, and once the patch is accepted upstream it nicely gets the tree back to the state that the user is familiar with. The problem is that rebase doesn't work with pull, so the user needs to un-learn git-pull and start using git-fetch; it's to avoid this that we recommend using git-fetch from the start, which is unfortunate since it makes things harder for beginners. -- Alexandre Julliard julliard@winehq.org -
Well, when I was using BitKeeper, I never would. Bitkeeper has what
Linus calls the broken "repository == branch" model. So normally I
would have one repository where I would track the upstream branch, and
only do bk pull into that branch. I would do my hacking in another
repository (i.e., branch), and periodically keep track wha was going
on in mainline by cd'ing to the mainline repository and doing the bk
pull there.
The challenge when you put multiple branches into a single repository,
is you have to keep track of which branch you happen to be in. In the
BK world, this was obvious because it would show up in my shell
prompt:
<tytso@candygram> {/usr/src/linux-2.6}
2%
(OK, obviously I'm in the Linux 2.6 upstream repository)
In a system where you need to keep track of what branch you are in via
an SCM-specific local state information, it's easy to get confused and
do a pull when you are in the "wrong" branch, or while you have local
state in your working directory.
What I currently do (and I'm sure I'm being really horrible and need
to be say 100 "Hail, Linus"'es for penance for not adhering staying in
the one true distributed state of grace) is that I keep an entirely
separate Linux 2.6 git repository just to make sure I never get
confused about what branch I might happen to be in when I do the "git
pull" --- and yeah, I could have used "git fetch", but 3+ years of BK
usage plus Hg usage is hard to get away from. I'm sure this is where
Linus would say that use of BK and Hg, causes permanent brain damage,
ala's Dijkstra's ofted quoted comment about use of Basic inducing
I think the problem is the people who have had years of BK or Hg
experience. Maybe it's more of a documentation problem; perhaps a
"git for BK" or "git for Hg" users is what's needed. The problem
though is that while use of BK is definitely legacy, there are going
Well, I think this is where git's learning curve challenges are. Yes,
for users that are doing the stupidest, most ...Err, what I meant to say is that there are going to be a lot of people who will need to simultaneously use both git and Hg. - Ted -
As a 80%-hg/20%-git user, I'm curious what features of git you had in
mind, so I know where to look as I wander up the git learning curve.
My experience with the git user interface, for what it's worth, is
that I never quite get the conceptual model crystal clear enough in my
head. So it won't stay for long enough for me to progress up the
learning curve and retain the gains. I move up a bit, but the gain
soon evaporates and I backslide, and then just hack my way through it.
I found hg's conceptual model very easy to learn, almost as if I don't
have to remember anything. Maybe that simplicity comes at a price,
whence my question at the start about the extreme-power features of
git.
-Sanjoy
`Never underestimate the evil of which men of power are capable.'
--Bertrand Russell, _War Crimes in Vietnam_, chapter 1.
-
I would agree that having "pull" mean something different in Cogito than in Git was a bad idea (explanation: historically, for some period of time Cogito had cg-pull which meant the same as cg-fetch or hg pull; later it got renamed to cg-fetch). But I'm also happy that Cogito just does not use the "pull" expression at all currently: "updating" seems to be a clear and unloaded enough concept for new people. Pull is really _very_ confusing, with it meaning something different (but not different enough) in _all_ other systems but BK (which is basically irrelevant nowadays). That said, I agree with your argument that changing it in Git now might just result in more confusion. I'm just trying to explain Cogito's choice here, and I believe it does no good nor harm to Core Git if it just uses different name for the concept and avoids the original name at all (except explaining in the docs that updating in Cogito is what pulling is in Git). -- Petr "Pasky" Baudis Stuff: http://pasky.or.cz/ #!/bin/perl -sp0777i<X+d*lMLa^*lN%0]dsXx++lMlN/dsM0<j]dsj $/=unpack('H*',$_);$_=`echo 16dio\U$k"SK$/SM$n\EsN0p[lN*1 lK[d2%Sa2/d0$^Ixp"|dc`;s/\W//g;$_=pack('H*',/((..)*)$/) -
How was/is fetch contaminated? -- Petr "Pasky" Baudis Stuff: http://pasky.or.cz/ #!/bin/perl -sp0777i<X+d*lMLa^*lN%0]dsXx++lMlN/dsM0<j]dsj $/=unpack('H*',$_);$_=`echo 16dio\U$k"SK$/SM$n\EsN0p[lN*1 lK[d2%Sa2/d0$^Ixp"|dc`;s/\W//g;$_=pack('H*',/((..)*)$/) -
I think "fetch" is sane. Its only problem is a missing symetrical counterpart verb, like "get" and "put". Nicolas -
If you're a dog owner, the obvious counterpart for "fetch" is "throw" ;) I think "get" and "put" would be bad, just because of confusion with "sccs get" (ie it has that "get this file" connotations). Maybe "fetch" and "push" aren't totally diametrically opposite, but really, I don't think they are that hard to understand either. We do have the BK legacy of "pull" implying a merge, and that's fairly fundamental. It's also true that in a lot of usage schenarios, what people actually _use_ is "pull" and "push", and no, they aren't mirror images (since push will _not_ do the merge), but at the same time, from a _usage_ standpoint they really _are_ each others opposites. You "pull" to get other peoples data into your branch (and once you've internalized local branches and the merge thing, you know what this means), and you "push" to push your changes out. It really _is_ the usage schenario, and using "opposite" words really _does_ make sense. It's true that _technically_ "fetch" is the opposite of "push", but at the same time, that really is about technology, not about usage models. You normally wouldn't do a "git fetch + git push" pair. You _can_ do so, but it's not the natural way to work - unless you're just doing a mirror service. Linus -
Yeah. You could always throw a branch to your dog. Or maybe we should introduce the concept of "bones" to GIT in place of Has SCCS really had a similar level of influence than BK or CVS in that The problem is the "usage standpoint" distinction that has to be made. Exactly because in GIT it is a bit distorted from what most people But that's exactly why newbies have problems. Instead of simply understanding the bare operation (fetch data in a branch _then_ merge it) they sort of need to abstract the concept of branch away because a "pull" does it all automagically. Which is fine as long as you're willing to ignore branch concepts altogether. But once branches are back in the picture for more involved operations then the "pull" word simply feels odd. Even more so with the local merge syntax. When I say to someone "just merge branch weezee with your current branch" the most intuitive command would be: git merge weezee But because "pull" mixes two concepts together this makes the thing more esoteric. Unless, of course, you get used to the mental model you outlined above, but IMHO simply needing a mental model to explain the tool is a sign that something is mapped wrong. Nicolas -
