7 ms·
I 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
by sakisv 3y ago
I 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).
- strifey 3y agoI love this explanation. One unfortunately confusing extra piece that some people might occasionally run into is that there are two types of tag. Most tags are what you describe: pointers (git ref) to a commit (git object) and nothing more. These are usually referred to as lightweight tags. There are also annotated tags that can contain a message, have a timestamp, and sha, etc. These are proper git objects that behave a lot like commit objects, except they're still typically only referring to another git object (commit).
- recursive 3y agoI thought I understood tags... But now what's a "proper git object"? Is there an improper git object? Is there a proper git non-object?
- oasisaimlessly 3y ago"proper git object" = anything that has its own unique hash.
- derefr 3y agoUnderneath the SCM plumbing, the "true core" of git is a content-addressable object store. (See https://git-scm.com/book/en/v2/Git-Internals-Git-Objects https://git-scm.com/book/en/v2/Git-Internals-Git-Objects) When you `git fetch`, git is asking the remote to walk a tree of objects — starting at the commit object that the ref points to — and deliver them to you, to unpack into your own object store. Git could in theory do a lot with just objects — with the whole "data state" of the repo (config, reflog, etc) just being objects, and then one toplevel journal file to track the hash of the newest versions of these state objects. (Sort of like how many DBMSes keep much of the config inside the database.) But git mostly isn't designed to do this. Instead, git's higher SCM layers manage their state directly, outside of the object store, as files in well-known locations under .git/. This means that this higher-level state isn't part of the object-store synchronization step, and there must instead be a domain-specific synchronization step for each kind of SCM state metadata where applicable. Tags are an interesting exception, though, in that while the default "lightweight" tags are "high-level SCM metadata" of the kind that isn't held in the object store; "annotated" tags become objects held in the object store. (To be honest, I'm not sure what the benefit is of having "lightweight" tags that live outside the object store. To me, it looks like tags could just always be objects, and "lightweight" vs "annotated" should just determine the required fields of the data in the object. Maybe it's a legacy thing? Maybe third-party tooling parses lightweight tags out of the .git/ directory directly, and can't "see" annotated tags?)
- nvy 3y ago>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. Can you elaborate on why that's helpful? I rarely get into a weird state with git but when I do it's almost always faster/easier to just delete the repository, re-clone, and re-apply my changes manually.
- CorrectHorseBat 3y agoWhen you accidentally delete a local branch or mess up a rebase you can use the reflog to retrieve your lost commits
- olddustytrail 3y agoIf you accidentally symlink the wrong file, would you find it easier to delete the whole directory and restore from backup, or just learn how to change a symlink?
- metabagel 3y agoGit is many orders of magnitude more difficult than symlinks.
- olddustytrail 3y agoIt isn't really. Spend a day learning it and you'll be like a superhero for your team.
- nvy 3y agoI just delete the symlink and create a new one.
- olddustytrail 3y agoAnd, likewise, just delete the reference and create a new one.
- sakisv 3y ago
- afiori 3y agoI believe that detached HEAD means that there is not a current branch, that is no branch will be updated the next time you commit. You can get to detached HEAD even if the commit is pointed to by a branch
- derefr 3y ago> pointers to commits Or to use the name git gives to that concept, "refs." Thus reflog :) Also, one thing that I've found hasn't occurred to most people using git, is that all the branch/tag/etc refs of your fetched remotes, are also refs, able to be referenced anywhere you can name a ref. For example, if you ever want to say "I don't care what's on this branch, don't fast-forward or merge or rebase, just overwrite my local branch with what's on the remote!" then that'd be: git checkout foo git reset --hard origin/foo
- sakisv 3y agoAh yes, the fact that git brings the remote stuff locally when you `git pull` and all the `origin/<whatever>` are just branch names is something that I realised only too late. As for the refs, yes, good point ;)
- xorcist 3y agoWhen you do 'git fetch'. The 'pull' is just an alias for fetch + merge (or rebase, depending on local settings).
- mjochim 3y ago> Or to use the name git gives to that concept, "refs." Thus reflog :) A command name that I read as re-flog for the longest time :D. I really wondered about the strange, strange name for quite a while before I bothered to look up what it does and found out that I should read it as ref-log and that it is, indeed, a very useful thing.
- trillic 3y agoThe humans will be flogged and reflogged until they understand the distributed version control
- xmprt 3y agoI had the same experience for the longest time until one day I'd have to "re-flog" my local git because I reset some commits that I shouldn't have. Turns out that flogging isn't a real thing in git let alone re-flogging the commits again.
- virtue3 3y agoReally great point and also really illustrates the tree structure underneath the hood for git and how it rules everything. The joke that isn't a joke is that you really need a CS degree to use git. It's not wrong. The git default arguments makes for a very inconsistent experience, agreed. And then `git checkout .` vs `git reset --hard/soft` vs `git cleanup` are all super similar but very different. Still love it more than perforce/svn (I did like mercurial a little better back in the day but I doubt that might still be the case). ----- `git reflog` is king and shows you the truth.
- sleepybrett 3y agoYeah anyone I run into that 'doesn't get git' and only has like the four commands they ever run... I point them at https://git-scm.com/book/en/v2/Git-Internals-Git-Objects https://git-scm.com/book/en/v2/Git-Internals-Git-Objects Once you internalize that git unlocks.
- cloudwalk9 3y agoI use Stable Diffusion (A1111 webui) and sometimes run into config issues, sometimes untracked by git. Nothing more catastrophic than doing `git clean -dfx` by habit from tinkering with Debian packages and knowing that command actually resets everything that `git reset --hard` doesn't... And then accidentally wiping out all of your checkpoints and generated images :')
- efreak 3y agoHardlink your checkpoints elsewhere, this way you don't have to keep them around elsewhere. Alternatively, make your models directory a symlink. (I don't think you can symlink the models themselves, I think that'll break it)
- mewpmewp2 3y agoYou can still use git and have it be useful even if you don't fully inderstand it, so I disagree with the CS degree notion.
- 3y ago
- sampo 3y ago> HEAD is pointing to the commit you're currently looking at HEAD pointer is pointing to the branch pointer (e.g. my-branch) which is pointing to the commit. (Except in a detached HEAD state.) > Every time that you make a commit on `my-branch`, then both the `HEAD` and `my-branch` move to point to the new commit. HEAD pointer keeps pointing at the my-branch pointer, and only the my-branch pointer moves to point to the new commit. But of course, when you now follow HEAD to my-branch to the commit, now you end up to the new commit. > "detached HEAD" means that the the `HEAD` (the commit you're looking at) is not pointed at by a branch. "Detached HEAD" means that HEAD is pointing directly to a commit, instead of pointing to a branch pointer. You can have a detached head state, where both HEAD and the branch pointer point to the latest commit. If you use `git log --decorate`, for the latest commit it will show (HEAD, my-branch) instead of the normal (HEAD -> my-branch).
- sakisv 3y ago> "Detached HEAD" means that HEAD is pointing directly to a commit, instead of pointing to a branch pointer. Ah, thanks for pointing it out, always good to learn the finer distinctions
- iamcreasy 3y ago> HEAD pointer is pointing to the branch pointer (e.g. my-branch) which is pointing to the commit. (Except in a detached HEAD state.) Yes! Here[1] is a nice picture about from Git Reset Demystified article. You can also see is in the following `git branch -a` output, * main remotes/origin/HEAD -> origin/main remotes/origin/main [1] https://git-scm.com/book/en/v2/Git-Tools-Reset-Demystified https://git-scm.com/book/en/v2/Git-Tools-Reset-Demystified
- jacobegold 3y agoI think that this video should be considered mandatory viewing if you're a developer using Git — the whole lecture starts from the basic data structures involved and builds from there, as opposed to the way that it seems many people approach Git: "What command do I run?" https://www.youtube.com/watch?v=2sjqTHE0zok https://www.youtube.com/watch?v=2sjqTHE0zok
- SAI_Peregrinus 3y agoThat's great evidence that git's UI is such a leaky abstraction that it's actually terrible.
- funcDropShadow 3y agoGit's UI is not meant as an abstraction at all. It is a set of tools to work on the underlying model. And the underlying model is actually quite elegant and understandable. I'd take that anytime over a leaky abstraction like subversion.
- keithalewis 3y agoBuh, buh, but Linus wrote it. There's got to be a pony in there somewhere. /s
- Terr_ 3y ago> 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. And if you're feeling extra-paranoid like me, a `git rev-parse HEAD` and copying that string down somewhere safe before embarking on a tricky process with lots of merge-conflicts or other shuffling. It's nice to have confidence that I've accurately identified which state is the last-known-good one--not one a few steps too far into the chaos-zone--and that I can usually get back to if everything goes to hell. (Barring unwise use of stuff like `git gc` or `git filter-branch`.)
- olvy0 3y agoOr putting a temporary tag on the current HEAD, so there's something I can return to later.
- SAI_Peregrinus 3y agoYep, HEAD isn't the head of any branch of the DAG, it's the CURRENT pointer to a commit. Why it's named HEAD shall forever remain a mystery. Quite a lot of git is conceptually simple, but the UI has quite a few confusing names & options.
- mdnahas 3y agoAND we should have pseudo-pointers to the current directory layout and the files already “add”ed (a.k.a. cached/indexed/staged). Git’s UI should allow us to do “diff” or any other command on these. I tried to get the git maintainers to name these (DIR and NEXT?) and make them work with the big commands, but they didn’t see the simplicity of it all. So instead of “git diff DIR NEXT” we get “git diff” and instead of “git diff NEXT HEAD” we get “diff —cached HEAD” which are much less understandable.