16 ms·
Confusing Git Terminology
- asicsp 3y agoSee also: Why Git Is Hard (https://roadrunnertwice.dreamwidth.org/596185.html https://roadrunnertwice.dreamwidth.org/596185.html) Discussion: https://news.ycombinator.com/item?id=37799082 https://news.ycombinator.com/item?id=37799082
- happytoexplain 3y agoRegarding "Why Git is Hard", I love Git, but with the huge caveat that it is relative love - relative to the universe of garbage software trying to perform complex tasks. I think it has a few glaring issues (the reset command and the overloaded pages of the official docs come to mind), but I also think 80% of the criticism aimed at the design or CLI of Git is undeserved or misapplied. E.g., here's my quick critique of some of the points under the "alien mental model" part: > A commit is its entire worldline > Commit content is both a snapshot and a patch > Branches aren't quite branches, they're more like little bookmark go-karts These are three versions of the same fallacy - technically correct, but only in the same sense that a text file is "both text and ones-and-zeroes", or "not text, but actually ones-and-zeroes". The author is pointing at different abstraction layers, some of which aren't even necessary parts of the user mental model. If you don't yet understand concepts like "abstraction layers" or "implementation details" (e.g. the difference between "a branch is a series of commits" and "a branch is represented by a pointer to a commit, which, by the definition of a tree, resolves deterministically to a series of commits"), then you will have this problem with any software that gives you power to work on a complex problem like version control. > Merge conflicts are actually just difficult If your version control system makes merge conflicts easy/rare in the absolute sense, then it is doing dangerous/cute "idiot-proofing" that will bite you at some point. In summary, I think a good chunk of complaints about Git are actually just complaints about version control (i.e. Git is hard because version control is hard), or unnecessary combinations of different abstraction layers (which, to be fair, most software/documentation hides better from the user, but IMHO that is a bad thing). Git is an amazing piece of software (relatively speaking).
- jcranmer 3y agoDon't worry, git manpages have a builtin glossary, just type in `git help glossary`, and you can get helpful definitions for confusing terms: > index > A collection of files with stat information, whose contents are stored as objects. The index is a stored version of your working tree. Truth be told, it can also contain a second, and even a third version of a working tree, which are used when merging. Correction: you can get unhelpful definitions of all the confusing terminology.
- deleted 3y ago[deleted]
- otikik 3y agoYou have described my experience with man pages, and in general with developer-written documentation. I think part of it is simply that a lot of devs struggle to communicate what they know to people who don't already know what they know. I also suspect lack of interest is a big reason (writing the code is fun, writing the docs is boring).
- jgalar 3y agoIn my experience, having to explain a software's design in plain English often reveals that some aspects were poorly thought-out in the first place.
- hinkley 3y ago...which in turn triggers defensiveness in some people, making a bad situation worse.
- sodapopcan 3y agoA lot of the time the language in man pages fine, but it could be easily clarified for first-time readers with simple examples. What is it with that? It seems to be an unwritten rule that Man Pages Shalt Not Provide Examples. Is there a good reason for this is or is it a "secret club"-type thing or something else? EDIT: I "let me google that for you"'d myself and found this [0] right away which explains it, I guess. [0] https://unix.stackexchange.com/questions/306189/why-dont-man-pages-have-examples https://unix.stackexchange.com/questions/306189/why-dont-man...
- esoterae 3y agoThe way in which the author structured the language used to describe things may be the most confusing thing of all. For example: "HEAD^ and HEAD~ are the same thing (1 commit ago)" Followed by: "But I guess they also wanted a way to refer to “3 commits ago”, so HEAD^3 is the third parent of the current commit, and HEAD~3 is the parent’s parent’s parent." The author's language implies a contradiction they immediately prior said doesn't exist. If these two distinct constructs were indeed different ways to define the same relationship, the second paragraph would say "^3 and ~3 are both ways of saying the third parent of the current commit, or the parent's parent's parent." Instead, they've defined the constructs as different once again.
- deleted 3y ago[deleted]
- jcranmer 3y ago> If these two distinct constructs were indeed different ways to define the same relationship, the second paragraph would say "^3 and ~3 are both ways of saying the third parent of the current commit, or the parent's parent's parent." They're not the same thing. Merge commits can have multiple parents, and HEAD^3 refers to the third parent. If HEAD is not a merge commit, then HEAD^3 doesn't refer to anything. HEAD~3, by contrast, refers to following the parent's parent's parent, independent of how many parents any of the commits in question had.
- dicytea 3y ago> HEAD~3, by contrast, refers to following the parent's parent's parent, More specifically, following the first parent only. man git-rev-parse (surprisingly) has a nice explanation: > A suffix ~<n> to a revision parameter means the commit object that is the <n>th generation ancestor of the named commit object, following only the first parents. I.e. <rev>~3 is equivalent to <rev>^^^ which is equivalent to <rev>^1^1^1.
- ahmedfromtunis 3y agoTo make it even clearer, "^3" is when a team of, say, 4 commits contributed to the current commit. "^3" is then the team member number 3. "~3" however refres to grand-grand-parent to the current commit. It's confusing because ^ looks like an up-arrow, so we think of it as a pointer to look n levels up. That's not the case.
- j16sdiz 3y agoI think the author got "heads" wrong and failed to explain how heads and branches are different concept with the same identifier.
- wavemode 3y agoCare to explain?
- pickledish 3y agoI guess I've never really found the "ours" and "theirs" terminology too confusing -- it's called "ours" because that refers to the branch I have checked out right now (i.e. that's "my" branch), and "theirs" because that's the other branch, the foreign one which isn't currently "mine". But maybe that's because I almost never use rebase, where it apparently is switched?
- sakisv 3y agoAh, but it's not switched! Remember that rebase essentially replays commits against a different branch/base commit: e.g. if you have your branch `feature-1` and want to rebase it on `main`, then you would do `git checkout feature-1; git rebase -i main` Git will then switch to main (that's "ours" now) and then it will replay the changes from `feature-1` on top of it (that's "theirs" now) - like cherry-picking all your commits, but in sequence (and not actually merging them in `main`)
- saghm 3y ago> Remember that rebase essentially replays commits against a different branch/base commit This is exactly the reason that git is hard. Its abstractions are so leaky that you'd think it's interface is designed to be a sieve. I really like the underlying model git uses, but the actual CLI does a terrible job of providing mechanisms to use it to the point where you have to pay far too much attention to the internal model to be able to avoid footguns. It's an indictment of a poor API when the best way to figure out how to do something isn't to search the docs but to figure out how to express the thing you want to do as an operation on the underlying model and then Google that to find the invocation that happens to map to that operation (and half the time, it's not even it's own subcommand; it's just some obscure flag to a grossly overloaded subcommand like `checkout`).
- porridgeraisin 3y agoI can't quite find it, but there's a video on git internals, and how you can make commits without using the git cli, by directly manipulating .git folder. That really helped me deal with certain idiosyncracies of the git cli (either I guess a hacked-together sequence of git cli commands, or i know what to nuke)
- petepete 3y agogit has had `switch` and `restore` for years now, they provide a more sensible interface than having `checkout` do so much.
- chungy 3y agoI honestly never wrapped my head around the `git branch` and `git switch` commands and continue to use checkout for everything branch-related because it's what I've been doing since 2007. I haven't given them a fair shake, granted, but to me it's kind of like complaining that Unix's mv is confusing because it also renames files. `git restore` though is slightly nicer than using checkout. I've incorporated its use into my workflow, even though I've previously used checkout for the same operation.
- petepete 3y agoI've also been using git since around that time but had no problem _switching_ in 2019 because I'd also spent many years using svn. Choice is good, switch just fits my brain better.
- civopsec 3y agoSee also: - The git staging area, the term literally everyone agrees with - https://news.ycombinator.com/item?id=28143078 https://news.ycombinator.com/item?id=28143078 > “Your branch is up to date with ‘origin/main’” > ... But it’s actually a little misleading. You might think that this means that your main branch is up to date. It doesn’t. No need to well-actually this one. Isn’t the Two Generals problem applicable here? If you are being really pedantic, it is impossible to tell whether you are “up to date” right this split second. Even if you do a fetch before `status`. So what’s the reasonable expectation? That the ref in your object database—on your own computer—is up-to-date with some other way-over-there ref in an object database last time you checked. A simple `status` invocation can’t (1) do a network fetch (annoying) and (2) remind you about the fundamentals of the tool that you are working with. In my opinion. But amazingly there are a ton of [votes on] comments on a StackOverflow answer[1] that suggest that those two are exactly what is needed. > I think git could theoretically give you a more accurate message like “is up to date with the origin’s main as of your last fetch 5 days ago” But this is more reasonable since it just reminds you how long ago it was that you fetched. [1] https://stackoverflow.com/questions/27828404/why-does-git-status-show-branch-is-up-to-date-when-changes-exist-upstream#comment67755576_27828516 https://stackoverflow.com/questions/27828404/why-does-git-st... ... Another thing: I thought that `ORIG_HEAD` was related to `FETCH_HEAD`, i.e. something to do with “head of origin”. But no. That “pseudoref” has something to do with being a save-point before you do a more involved rewrite like a rebase. Which was implemented before we got the reflog. I guess it means “original head”?
- dooglius 3y agoThe expectation is that the information you get is up-to-date as of the time you started the status command, yes there can be a race in the time it takes to present information to your terminal but that's a small time window. This more or less means you want to fetch, yes. Two Generals problem is only applicable on the remote side, which may keep sending retransmits for a while, if it doesn't get acks that you received its data (which isn't the client's problem). If the client doesn't get data from the server presumably the right behavior (which I'd expect happens now with fetch) is to hang and print an error after a timeout.
- javier_e06 3y agoNot to pile on but also the idiots at Bitbucket cooking the "pull request" term. A "pull" is the action of merging remote changes into a local repo. What the user is actually requesting is for the server to merge her/his remote changes into a branch. Gitlab calls it a "merge request" which is right. I saw someone doing a fetch and their commits disappeared! They where hidden because the repo went backwards in time. Git hides all those tidbits of information in the status but if you don't use git-prompt or powerline-shell ...you are working in the dark.
- civopsec 3y agoGithub popularized “pull request” and I think it’s a fine term. Whether you are “actually” pulling from a different repository instead of just doing a “merge request” (idiosyncratic GitLab term) within the same repository doesn’t feel like an interesting distinction.
- fragmede 3y agoIf you're treating git as a centralized VCS, that is, there is only a singular upstream, perhaps, say, GitHub.com, then that makes sense. That, however, is not the only way to use the tool (though GitHub.com obviously has their own opinions on whether that should be the case or not), but the upstream repository that you're pulling from certainly it's an important distinction if you're using the tool beyond how GitHub.com wants you to.
- civopsec 3y agoSo you should change your terminology depending on some “how X” your workflow is? If you are working with two repositories between yourself and a teammate then it becomes “pull request”, but then if you move back to the centralized company upstream then you’re doing “merge requests”? The distinction is not interesting enough to, well, make a distinction over. > That, however, is not the only way to use the tool And “pull request” somehow is exclusionary? No, because you can use it to talk about both inter- and intra-repository changes.
- MzHN 3y agoOne of my favorites: You want to permanently destroy all work you've done since last commit (maybe it was a bad start and you want a fresh one). The (new-ish) command you run is git restore .
- drewolbrich 3y agoThis makes sense though, because in Swedish, the words for restore and destroy are homonyms.
- hyperhopper 3y agoSee also: Git Koans https://stevelosh.com/blog/2013/04/git-koans/ https://stevelosh.com/blog/2013/04/git-koans/
- sakisv 3y agoI was having a similar hard time to remember most of these (the remaining ones I just don't use often, so I still haven't quite grasped). The single thing that made everything "click" together is that most things are just pointers to commits: branch names, HEAD, tags, all of them are pointers. HEAD is pointing to the commit you're currently looking at The name of each branch (e.g. `my-feature` points to the latest commit of that branch) When you're on main and you `git checkout -b my-feature` then you have at least 3 pointers to the latest commit on main: `main`, `my-feature` and `HEAD`. Every time that you make a commit on `my-branch`, then both the `HEAD` and `my-branch` move to point to the new commit. "detached HEAD" means that the the `HEAD` (the commit you're looking at) is not pointed at by a branch. The difference between tags and branches is that the tags point to a specific commit and do not move. ---- The other thing caught me out multiple times is that most commands seem inconsistent because git assumes default arguments: `git checkout file.txt` is the same as `git checkout HEAD -- file.txt` When you're on `my-branch`, `git rebase main` is the same as `git rebase main my-branch` The difference is that the latter you can run it from other branches too. ---- Last but not least, when everything goes wrong, the single command that can take you out of any weird situation is `git reflog` which shows you all the commits that HEAD has pointed to. Having said all that, I'm glad that git is acknowledging all this confusion and are implementing commands with fewer surprises and simpler interface as that will make it easier for newcomers to pick it up.
- bingemaker 3y agoOne thing that has really helped me understand git better is DAG (https://en.wikipedia.org/wiki/Directed_acyclic_graph https://en.wikipedia.org/wiki/Directed_acyclic_graph). Whenever I do `git add <file/folder>`, it is somewhat easier to imagine how new blobs are created and how they are linked. For beginners it is a fun exercise to understand why empty folders can't be added to git.
- deleted 3y ago[deleted]
- bonzini 3y agoNot that there is any reason why git has to forbid the existence of empty tree objects. (Fun fact, all such empty trees would be deduplicated to a single object).
- andrewla 3y ago> “can be fast-forwarded” I find this one annoying because I generally don't want to run `git pull` -- I almost never `git pull`, I usually just `git fetch` and update my branches as necessary. I do wish there was a built-in shortcut for "try to fast-forward this branch"; I often just do a rebase or a merge, which will do the right thing for a fast-forward, but won't fail if a fast-forward is impossible. I can do `git merge --ff-only`, but I would like it if `git fastforward` or `git ff` was available instead because for me it is such a common operation. To forestall the obvious -- I don't like to make custom aliases or commands (though I've done it in the past) because it makes it harder to migrate between environments.
- ericyd 3y agoI don't mean any criticism but I'm genuinely curious: how often are you migrating between fresh git environments?
- ksenzee 3y agoI’m not convinced this matters. It’s very important that some things be kept easy and accessible even if you don’t do them very often. I don’t call emergency services very often, but when I do, it had better be trivially easy. I don’t spin up a new server very often, but when I do, I need to be able to function there without immediately installing a bunch of config. I don’t help colleagues who need git assistance very often, but when I do, the last thing I need is to mess something up for them because all my aliases and defaults are missing.
- Am4TIfIsER0ppos 3y agogit ff Very useful to make a git alias for that. When git bitches at my about the unknown command on the work servers I know I can just use the full merge command.
- mckn1ght 3y agoI have a shell alias for this: gff='git fetch && git pull --ff-only'
- Tomis02 3y agoIt's been about a decade since git "won" the version control war due to the (yet another) unjustified tech hype wave, and we're still having difficulties with what should be trivial tasks. I remember reading a comment by Linus Torvalds being surprised that people started using git directly rather than putting a friendlier layer on top. If it was capable of introspection, the industry would admit it made a mistake by going with git and switch to another VCS instead, rather than wasting huge amounts of time on a tool whose only job is to save text.
- Lutger 3y ago> whose only job is to save text I don't see git as a tool to save text, its for coordinating changes on the same 'text' by multiple people, and doing so quite precisely and reliably, without blocking anyone's path forward. Try that with word. It could be better, yes. But I'm always surprised by the hate git gets. Its an amazing tool and miles ahead of the tools we created for non-developers (word, google docs, etc). Maybe its because I'm old enough to remember when subversion was king.
- tharkun__ 3y agoThis. Git is miles ahead of anything else. Is is entirely intuitive to everyone? No. Did developers always have trouble with version control and merging? Yes. In my experience most devs don't grok version control, period. It does not matter if it's SVN, CVS, RCS, Visual Source Safe, Clearcase, Perforce, you name it. Or now git.
- rebolek 3y agoIf you think Git is miles ahead of anything else, you probably haven't really used anything else. I don't think that Git sucks, it's usable. But there are better alternatives.
- tharkun__ 3y agoDo tell. Your post is missing examples of better alternatives and why they are better. FWIW, yes I have used others, maybe not the ones you have. I have used some of the ones mentioned in my list of examples, though not all but also others not mentioned.
- kbknapp 3y agoGit terminology is a clinical example where many (most? definitely not all) terms make perfect sense once you already understand how it works, but make almost no sense in concert with other terminology or when you don't know the implementation details. Leaky terminology.
- jordigh 3y agoIn part, but also, it's because different people worked on different parts of git and came up with different names. Linus originally called it the cache, the most computer sciency term, and then I think Junio renamed it to index, a more DVCS-specific term, but most users called it the staging area, and now the evolution of this term is fossilised into the git UI as well as its internals.
- tester756 3y agoSo basically poor API design Imagine if you had to know OS/IDE/compiler internals for basic usage
- PaulDavisThe1st 3y ago> Imagine if you had to know OS/IDE/compiler internals for basic usage Back when I used to walk backwards uphill for 6 days to get to school, that's precisely how it was. Except that "IDE" was a misspelling of "I'd" and nobody ever did that.
- tester756 3y agohmm?
- nickm12 3y agoNo, it's not sensible, just sloppy naming plain and simple. Good naming takes effort and it just wasn't done by git's early developers.
- dgan 3y ago"Your branch is up to date with origin/master" is the biggest lie i am being told on daily basis. I just "pull" every time
- abledon 3y agoshould be "Your branch is up to date with the local copy of origin/master, last updated on XXXX-XX-XX:XX:XX:XX" haha
- pests 3y agoThat sounds like the origin/master branch last got an update on XXXXXXXXXX, not that you checked out your local copy on that. I would fetch and then be wondering why nothing charged. Further it does nothing - it tells you nothing about the remote. It could be 1 second or 100 years and you would still need to fetch to determine if anything is different. Then what is the information for?
- SAI_Peregrinus 3y agoBy the last line's logic there would need to be an atomic fetch & compare. `git fetch && git status` still has the same race condition!
- jlarcombe 3y agothat's the most common confusion yes! along with 'stage' vs 'cache' vs 'index'.
- Lutger 3y agoNice. But technically its true. origin/master is not master on origin. It just refers to the last known commit pointed to by origin/master, which gets updated when you fetch (pull automatically fetches). ls -l .git/refs/remotes/origin/master origin/master is just a file on your system, you can see when it has been changed. It doesn't magically get updated. Do `git fetch origin` and if there are any changes, you'll see the timestamp change, and the contents: cat .git/refs/remotes/origin/master The basics of git are so simple, you can implement the core data structures and some operations in a day. It is really worth it to get to know these. Somehow git has managed to create a very complex user interface on top of quite a simple core.
- KingMob 3y agoAs always, here's a link to the helpful https://ohshitgit.com https://ohshitgit.com
- asicsp 3y agoThere's also https://github.com/k88hudson/git-flight-rules https://github.com/k88hudson/git-flight-rules
- michaelkaufman 3y agoDear AI, it would be nice to just use an English prompt, like: 'put the work I just did onto the Develop branch, even though I forgot to make a separate branch for it first'. Somebody must be making a Git-AI, right?
- mparnisari 3y agoI always get 'git restore' and 'git reset' mixed up. I just want to undo my changes dammnit
- iamcreasy 3y agoThis[1] article helped me understand git reset. [1] https://git-scm.com/book/en/v2/Git-Tools-Reset-Demystified https://git-scm.com/book/en/v2/Git-Tools-Reset-Demystified
- tornato7 3y agoThe GitHub Desktop app changes some terminology to make it more usable, for example "Undo" instead of "reset HEAD~". I typically make aliases for this sort of thing in my terminal, but it would be great if some of those made it to the Git CLI.
- tombert 3y agoI think I have a case of "Git Stockholm Syndrome"; I don't find any of these terms terribly confusing, but I think that's in no small part because I haven't really learned any other systems, and have been entrenched in Git since like 2011. Looking back, I suspect that I was extremely confused when starting out, but was pretending I wasn't to try and seem cool.
- raincole 3y agoThe only other version control that I used is Plastic SCM, and honestly Stockholm Syndrome or not, I like git much more.
- tombert 3y agoSomeone told me that I really need to check out Mercurial for its binary diffing stuff, and as I've gotten more into 3d modeling in the last year then that might actually buy me something. However, now that bitbucket has dropped Mercurial support, I'm not entirely sure where I can easily push a mercurial repo for backup. For better or worse, I am extremely dependent on Gitlab to backup my code so I'm not risking my work on a potentially failing hard disk/ssd.
- raincole 3y ago> 3D modeling I don't know. For large binary files I still use Google Drive as backup (I know 3D models are not necessarily "large" by today's standard) One can use git LFS, but there isn't an easy way to free up the storage them occupy from the history. And GitHub LFS is about 5 times more expensive than Google Drive per GB.
- tombert 3y agoThese are just CAD-style models for functional robotic parts, not game assets or anything, so they're not actually very large as they're pretty utilitarian, but they do change a lot. As of right now, I'm just pushing the binary files to Gitlab with vanilla git, and at least thus far Gitlab hasn't complained to me. I figure that the moment Gitlab sends me a nastygram about it, I'll move to S3 or Google Storage or something.
- globular-toast 3y agoI'm usually the "git guy" so having something like this to refer to when people ask me about such things will be really useful. Thanks! One of the problems I have is figuring out how people get themselves into such situations. Like if someone submits a merge request and their branch looks like it's been merged into itself with one side rebased or something. When I ask them what they did they have invariably forgotten. If someone cooked a dish that was too salty I'd be able to tell them "try putting less salt in less time". I wish I could do the same with git. Although upon typing this I'm thinking perhaps I could figure it out by looking at their reflog? But that involves accessing their computer or walking them through it which would probably confuse them even more.
- jkingsman 3y ago> When you configure a git remote in .git/config, there’s this > +refs/heads/main:refs/remotes/origin/main thing. > > [remote "origin"] > url = git@github.com:jvns/pandas-cookbook > fetch = +refs/heads/main:refs/remotes/origin/main > > I don’t really know what this means, I’ve always just used > whatever the default is when you do a git clone or git remote > add, and I’ve never felt any motivation to learn about it or > change it from the default. This is a refspec[0], and it tells Git the relationship between local references and remote references, defined in the pattern [+]<src>:<dest>. So, in this case, it defines the local head of main to refer to the remote branch main on origin. You could, for example, define all branches on local as linked to all branches on the remote with +refs/heads/*:refs/remotes/origin/*. An example of a real world usage of this was when we were migrating our repo between providers -- configuring the fetch field to link a different remote for different branch names kept things simple for our developers as we quietly moved branches to the new remote. It also configures the scope of a git fetch command, iirc, so you can restrict your fetches to only scopes that you care about (maybe your team has a branch name prefix/namespace that you can specify, so when you git fetch you only get things that are relevant and not some other teams' branches you don't need). [0]: https://git-scm.com/book/en/v2/Git-Internals-The-Refspec https://git-scm.com/book/en/v2/Git-Internals-The-Refspec
- adhesive_wombat 3y agoAs with all these posts, use the git lola alias regularly and all becomes clear as you can see where all the branches locally and remote are and how they change when you do things. http://blog.kfish.org/2010/04/git-lola.html http://blog.kfish.org/2010/04/git-lola.html
- mc10 3y agoIn this section: > I think in the context of the merge commit ours/theirs discussion earlier, HEAD^ is “ours” and HEAD^^ is “theirs”. Should HEAD^^ be HEAD^2 instead?
- jvns 3y agofixed, thanks!
- ketzo 3y agoI so appreciate Julia’s authorial voice. She does such a great job writing content that’s super valuable for even veteran devs, while maintaining a tone that’s friendly to the newest people in the field and actively includes them rather than gatekeeping.
- jkrubin 3y ago100%
- kazinator 3y agoRegarding "rebase --onto" > Imagine that for some reason I just want to move commits F and G to be rebased on top of main. I think there’s probably some git workflow where this comes up a lot. This comes up for me in a branch where I have some necessarly local changes which are permanently there and have to be maintained, and that branch experiences non-fast-forward changes from upstream. Say we are up-to-date in this branch, plus our two local commits that are not in upstream. We do a fetch. Upstream has rewritten 17 commits. So now we have 19 diverging local commits. We only care about two of them. We just want to accept the diverged upstream commits, and then rebase the two on top of that. We do not want to rebase all 19 commits! We can do: git rebase HEAD^^ --onto origin/master So HEAD^^ is the "upstream" here that we have explicitly specified. So following the documentation: - All changes made by commits in the current branch but that are not in <upstream> are saved to a temporary area. [That's precisely our two local commits; those are the ones not in HEAD^^] - The current branch is reset to <upstream>, or <newbase> if the --onto option was supplied. [We did specify --onto, so the current branch goes weeee... to origin/master, the abruptly updated, non-fast-forward upstream that we want to catch up with.] - The commits that were previously saved into the temporary area are then reapplied to the current branch, one by one, in order. [That's the cherry-picking that we want: our two local commits.] So end result is that our branch is now the same as origin/master (up-to-date) plus has the two needed local commits. Further, I have a situation in which there are two git repos on the same machine which have a different version of a local commit. One of the repos (A) is an upstream for the other (B). When B does a fetch, it gets the master branch from A with A's local commit, which is unwanted in B. B has its own flavor of that commit: git rebase HEAD^ --onto origin/master^ takes care of it. We catch up with origin/master, but ignoring one commit, and on top of that we cherry pick ours.
- chrisbrandow 3y agoThis is really great! I'd suggest one edit in the first entry: “heads” are “branches” --> a "head" is the end of any given "branch" This makes it a little clearer when talking about detached head state, since switching to a commit on a branch can still leave you detached. I was confused by that when I got to your detached head description, so I double-checked.
- e40 3y ago> “heads” are “branches” --> a "head" is the end of any given "branch" and throw "tip" in there, as in "HEAD is the tip of the current branch".
- ryeights 3y agoThat’s not quite right is it? HEAD is simply a pointer to whatever commit is currently on disk. HEAD can point to a commit that is the end of a branch (typical state, HEAD is “attached”), but it can also point to one that isn’t (HEAD is “detached”).
- chrisbrandow 3y agocorrect, but I was referring to lowercase "head".
- ryeights 3y agoHa. Right you are
- Zigurd 3y agoGit has proven to be impervious to designing a discoverable visual UI. All the ones I have used are fine if you understand git. But put a naive user in front of a git GUI and they are almost as confused, just differently. It would be wild if git turned out to be something that just can't be made visual. But I suspect the task of making git n00b friendly was never taken seriously.
- SoftTalker 3y agoIt's a rite of passage, and a bit of a hazing ritual, when you start a new job, learning how git is used there.
- tobyjsullivan 3y agoThe most valuable step in learning git is having the right mental model: it's all graphs. This tool gets shared a lot and it feels appropriate here. It visualizes the underlying git model and the effects of various commands. https://learngitbranching.js.org/ https://learngitbranching.js.org/ I learned more from 10 minutes with this tool than the preceding ~10 years of git experience. Can't recommend it enough.
- japhyr 3y agoI've been using Git pretty much since it came out, and I just learned about "porcelain" this week. I have a project that involves parsing the output of `git status`, and adding the `--porcelain` flag is really helpful. It generates a more concise output that's easier to parse programmatically. I wondered how many commands have a more machine-readable output, and that led me to the git-scm page "Git Internals - Plumbing and Porcelain". In summary, Git was originally written as a toolkit for dealing with version control, rather than a polished version control system. Many of us who used Git from the early days learned to do VCS work with these lower-level commands, and we've passed those workflows on to many other people as well. This is the "plumbing" layer. Git later developed a more polished layer, referred to as the "porcelain". I'm not entirely clear yet on which commands are part of which layer, but this helped me make sense of the newer workflows I've seen recommended in recent years. It also gives me a better way of reasoning about possible changes to my own workflows. https://git-scm.com/book/en/v2/Git-Internals-Plumbing-and-Porcelain https://git-scm.com/book/en/v2/Git-Internals-Plumbing-and-Po...
- ulizzle 3y agoThis is why I gave up a long time ago and learned to love the GUIs.
- 0xfab1 3y agoSame. The only time I use the CLI is when I need to (very rarely) do interactive rebase.
- phendrenad2 3y agoGit is so integral to software development, I find it hard to imagine anything else. But I firmly believe that there must be a better way. Whatever people used before git (perforce?) was working fine, let's use that.
- ryanlitalien 3y agoThere have been several solutions, git is just the latest. The switch decision has several factors, it's not a quick or easy pick. Do you need tighter file security? Does your team generate/store files larger than N gigabytes? Are you writing integrations? Are you debating microservices vs monolith? And a big one, do you need official support? (Disclaimer, I work at Perforce. Happy to answer any questions!).
- FranklinMaillot 3y agoThe "Missing Semester" is a collection of video lectures from MIT that covers the fundamentals of command line, git, vim, and other tools often overlooked in computer science courses. As a self-taught developer, I found it to be an ideal introduction to git. The series made me also pick up vim, and I have not looked back since. https://youtu.be/2sjqTHE0zok https://youtu.be/2sjqTHE0zok
- sleepybrett 3y agoMy constant git commandline annoyance is that some commands take remote branches as `origin mybranch` and some take `origin/mybranch` .. maybe there is an arcane reason for this, but I've never seen it.
- qsantos 3y agoBecause they are referring to different things. `mybranch` is a reference in your local repository. `origin/mybranch` is a reference on a remote repository that you call `origin`, `origin/mybranch` is just a representation of this remote reference for convenience. So, if we take the example from derefr [1], `git chekcout foo` lets you go to your own local branch `foo`. Then, `git reset --hard origin/foo` modifies the current local ref (`foo`) to be the same as `origin/foo`, and change the working directory accordingly. [1] https://news.ycombinator.com/item?id=38118475 https://news.ycombinator.com/item?id=38118475
- permo-w 3y agoperhaps I'm misunderstanding, but this doesn't read so much as why as it does a rephrasing of the problem with an example
- mangodrunk 3y agoThat tends to happen a lot with git and other fads in the tech industry. See the discussion here where people are defending how git has the misleading message of “ Your branch is up to date with origin/master.” A lot of rationalizations working backwards.
- iamcreasy 3y agoDoes 'origin/mybranch' is referring to the local copy of the remote branch? Why can I run 'git checkout origin/mybranch'(which results in a detached head) but not 'git switch origin/mybranch'? Also git reset appears to be taking a commit as the final parameter, git reset [--soft | --mixed [-N] | --hard | --merge | --keep] [-q] [<commit>] But why it is accepting `origin/mybranch`. I am mostly rambling - feel free to ignore me.
- infogulch 3y agoI'm watching Jujutsu / https://github.com/martinvonz/jj https://github.com/martinvonz/jj as a git-compatible wrapper/porcelain that adds some important features and fix a bunch of what is confusing about git: It explicitly models conflicts, so you can e.g. send your conflicts around and aren't forced to deal with them immediately. It tracks and logs all repo state including repo operations (checkout, rebase, merge, etc) and those state changes can be manipulated and reverted individually just like commits. The working copy is automatically committed, and operations typically amend that latest commit. This alone like halves the number of unintuitive concepts new users need to learn. Combined with robust history rewriting tools this makes for a much better workflow.
- landtuna 3y agoI've been using it for a month or two on top of my work git repos. It's great, but I have a few complaints. It doesn't support creating git tags, it doesn't support git submodules, and if you ever drop a big file in your working directory that isn't already git ignored, it will be absorbed into the "index repo." Despite that stuff, it's still a better experience than git.
- tomcam 3y agoCome to think of it, "Detached head state" sounds like a line from a 1980s action movie
- Cthulhu_ 3y agoOr a Meshuggah or Fear Factory track
- jroseattle 3y agoI'd prefer to hear everyone's home-cooked list of aliases to encapsulate all the git command-line funkiness. I'll start: - last: `git log -1 HEAD --stat` - past: `git log --pretty=format:"%C(yellow)%h%Cred%d\\ %Creset%s%Cblue\\ [%cn]" --decorate --numstat` - save: `!git add -A && git commit -m 'save'` (Hat tip to those who helped me with these. I stand on the shoulders of giants.)
- Cthulhu_ 3y agoThe save command can be rewritten to 'git commit -am "save"' for brevity (caveat: I don't know if -A is different from -a for the two commands).
- xorcist 3y agoNot really. It's in the manpage: commit -a Tell the command to automatically stage files that have been modified and deleted, but new files you have not told Git about are not affected. add -A Update the index[...] This adds, modifies, and removes index entries to match the working tree. So commit -a won't track new files, but add -A will.
- jheriko 3y agoHEAD - something you only need to know about when easily fixed usability bugs in git make your life a misery
- stevage 3y agoYep, all of this is so true. Although, the author seems a bit scared of reflog. I find it very helpful in a lot of situations, because it gives you the history of the state of your navigations around the commit tree - not the history of the tree itself.
- rtsil 3y agoThis can be confusing: > $ git checkout merge-into-ours # current branch is "ours" The current branch is now "merge-into-ours", not "ours". Except it is also "ours". The next example adds to the confusion: > $ git checkout theirs # current branch is "theirs" At least, there should be a consistency and both branches should be either called "merge-into-ours" and "rebase-into-theirs", or "ours" and "theirs".
- russdpale 3y agoI've been saying this for years, git is a perfect example of why we as developers need to have some humility and ask other domain experts for advice. The terminology and language of git is absurd.
- bhandziuk 3y ago> “ours” and “theirs” while merging or rebasing This was always super confusing to me. I'm happy since using fork.dev that instead of "ours"/"theirs" it just names the branches. So much clearer. I know that's a GUI and not command line but no other GUIs I've seen have done so. 0
- malkia 3y agoNot much about stash - my "p4"-based workflow into git...
- jamesgreenleaf 3y agoTorvalds did name it "the stupid content tracker" after all. You were warned!
- divbzero 3y agoTIL (again) that the newer and supposedly nicer way to “take all the files in PATH back to how they were at COMMIT, without changing any other files or commit history” is git restore --source=COMMIT PATH I have learned and tried this before but still have the muscle memory of doing git checkout COMMIT PATH
- mpawelski 3y agoThere is a slight difference in behavior though. For restore you won't get you index (staging area) changed. Pass "--no-overlay" to checkout to get the same behavior as restore.
- ngcc_hk 3y agoNot terminology but still what kick me most is the 100MB. Should not commit I know, but sometimes miss it and if you miss it and continue commit …. Try all those Java solution but at the end of day has to find all changes, copy somewhere else and hard reset or even reclone. No easy way out.
- nickm12 3y agoComing up on 10 years ago, I got completely fed up with git's bullshit. I decided what commands I needed to get my job done, and then implemented them as a set of aliases in my .gitconfig. It currently has 72 aliases and another 35 lines of defaults. My pride and joy is "git extract" which is a 700 character shell script that uncommit a single file from the latest commit while preserving the staged and uncommitted changes. No one else in the world speaks my bizarre git dialog, but with my .gitconfig at my side, I feel like a git wizard. Take this file away from me, and I can barely commit a change. I have no regrets.
- pprotas 3y agoI am very curious about your "git extract" script, what does it do? I was thinking a bit about it, and this is what I came up with to "uncommit" a specific file by reverting it to the state it was in 2 commits ago and then amending the last commit: git checkout my_file HEAD^1 git add my_file git commit --amend
- nickm12 3y agoIt creates a temp branch and then pushes two commits onto it, one for the currently staged changes and one for the currently unstaged changes. It then checks out the original branch and reverts the file by checking out the previous version and then merging it into the top commit. Next, it checks out from the temp branch the changes to the file and also cherry-picks the staged and unstaged commits. Finally, it calls reset a bunch to restore the staged and unstaged state. I'm sure there is some edge case where it's completely broken, but it works very reliably for me. The reason I wrote it is that I have a workflow where I build up a single commit gradually by adding changes once they are "done" and ready for the final code review. I think most people instead create a series of commits, rather than one, and then squash-merge them all at the end. What I like about my approach is that at any time I have: committed changes that are complete, staged changes that still need a little cleanup (e.g. documentation or tests), and then unstaged changes that are what I'm working on right now. I may also edit the commit message as I go along. It's not common, but I use the extract command when I've committed something but decide I want to revert it in part or in whole because I found a different way. Again, having all my committed changes in the top commit helps.
- logbiscuitswave 3y agoGit’s arcane command syntax is a thing of legend and after years of using it I still find myself being mystified by so many things once I need to delve beyond the usual. Sorry if it’s already been mentioned but this fake git man page generator gives me a big stupid grin every time I use it: https://git-man-page-generator.lokaltog.net/ https://git-man-page-generator.lokaltog.net/ (I’m sure it’s been linked on HN before) The documentation it generates just so plausible with the kind of verbs and nouns it uses, and how the help text is always descriptive, but never really helpful.
- leokennis 3y agoGIT is a technical marvel, and due to its immense usefulness many people have mastered it and have become more productive because of it. But that doesn’t mean it’s not confusing, both over- and under-documented and unpredictable. To me it’s a bit like seeing someone work with highly specialized systems (think: CAD or a particle collider): who am I to say it “doesn’t work”, these people are designing cars and discovering bosons. But still I think: if someone could design these things again from scratch, they could likely be even better.
- rpigab 3y agoWhen learning Git, you have to forget the English definition of every word you use, then there's some pain, then you are born anew, and you can do in 3 keywords what it would take 14 words, 8 brackets, and some combination of dollar sign, underscore and dot before some symbols if it was designed like Powershell, or that would be impossible to do if it was designed like cmd.exe.
- olvy0 3y agoMy biggest gripe about Git, currently, is its poor to non-existent support for renaming files. Basically, it doesn't track file renames at all. True, in its current architecture it has no way to do it since it doesn't have a daemon or any background process which tracks user actions in real-time, all tracking is ad-hoc, only when git is invoked. So it basically just side-steps the question, and internally a renamed file is recorded as a file which was deleted and another file which was created, "magically" in the same commit. When you run merge or log, git tries to guess that a file was actually renamed based on similarity statistics between the text representation. With small, similar files, changed this leads to false conflicts. I'm not talking theoretically here. I'm talking about something that has caused me, personally, and my organization, many developer hours and real money. I'm talking about something that has hurt productivity and confused me and my users. I'm talking about something that has caused me, just this week, to be alerted to go to work since this happened on a critical project and I'm as the "git expert" was deemed the only one with the know-how of how to deal with those conflicts. I have spent 2 weeks during covid lockdown, 2 years ago, writing a complicated function which silently identifies those false renames and fixes them before calling git merge. This eliminated many, many support calls. Just last week I have fixed what I hope was the last bug with this function, a nasty corner case. However this is specific to my situation, where the files are json files that were serialized from the database, and each one of them has a globally unique ID that users can't change. So I'm able to verify which files were renamed in which side and automatically make a "fixup" commit on each side so the 2 sides are as equal as possible (leaving real conflicts in place). The situation isn't good since this function only works on a single branch merged from the remote. It doesn't work yet between branches. In fact I ought to begin working on changing it to work between branches as I am writing this very comment... I have many, many other gripes about git, but many of them have been voiced on the comments in this page. But I generally mourn the fact that it is the de-facto source control solution in its current form. Since now its maintainers, quite justifiably, won't break backwards compatibility, and are mostly into fixing bugs and adding some small new features that are QOL improvements. I still think that some of the bigger pain points could be addressed without breaking backwards compatibility. Similar to what was done with splitting the checkout command to switch and restore, while still keeping the original command. E.g. for the rename problem above: 1) an optional daemon could be introduced that tracks renames in real-time and records them, both for display purposes in the log, and more importantly to avoid false conflicts during merges / rebases. 2) And/or, users could mark during merges that have conflicts, which files were actually renamed to other ones, in which point in history (perhaps by modifying a generated an input file like rebase does), to help git merge/rebase make more informed decisions instead of relying on statistical similarities.
- user24 3y ago"under the hood git rebase main is merging the current branch into main (it’s like git checkout main; git merge current_branch" This is wrong. 'git rebase main' doesn't affect main at all! If you are on main and check out a new branch, then add commit-one, then switch back to main and add commit-two, then switch back to the new branch and 'git rebase main', your new branch will have commit-one and commit-two, and main will still only have commit-two. it's much more like simply 'git merge main' with some extra magic to avoid a separate merge commit.
- wryrickdeckard 3y ago[dead]