Jump to content

Git detatched head. All of a sudden this makes sense!


Recommended Posts

This morning I finally realised why I semi-regularly get into a detached head state (I think I know why...).

In git there are several different options for checking out a commit (checkout commit, checkout branch etc) and I never really paid much attention to the subtleties of these. As far as I thought they all did the same thing, that is revert the local code to the state of that commit.  It turns out that my understanding was flawed, and every time you check out a single commit (rather than the actual branch) the current state will not point to any particular branch and you will be in the detached head state.

I find this a bit weird, as I presumed if you checkout a commit in say the middle of a branch somewhere you would still be on that particular branch. Checking out a branch will always checkout the latest commit of that branch.

This article explains it nicely.

I have not been too scared of detached head for a while now as I know it can be easily fixed just by making a new branch, but it is nice to know why this actually happening.

Happy gitting!

(next step in my git mastery is to understand the subtleties of local and remote branches).

Link to comment
2 hours ago, Neil Pate said:

All of a sudden this makes sense!

🙌 🎉 🎊 🥳

 

2 hours ago, Neil Pate said:

I find this a bit weird, as I presumed if you checkout a commit in say the middle of a branch somewhere you would still be on that particular branch.

What if you check out a commit that is part of multiple branches at the same time?

 

31 minutes ago, drjdpowell said:

"Git Branches aren't branches; they're just tags pointing to commits" is the first thing one needs to understand about Git.  

Indeed.

 

2 hours ago, Neil Pate said:

(next step in my git mastery is to understand the subtleties of local and remote branches).

There's not much I can offer that's not already excellently covered by websites like the one you linked.

So, I'll offer some fun facts instead:

  • A "remote" repository is usually located on a different machine, which is usually a server. But, the "remote" can also located in a different folder on your local machine. Try it for fun and for education.
  • You usually set your local repository to track a remote repository, which is usually on a server and considered the "authoritative"/"master" copy. But at the same time, that remote repository also could choose to track you -- such that from their POV, your copy of the repository is their "remote".
Link to comment
3 hours ago, Neil Pate said:

next step in my git mastery is to understand the subtleties of local and remote branches

When you add a commit to your local branch, it advances the branch pointer to that commit. The remote branch is not affected. Only when you push your changes to the remote does it forward the branch to the same commit.

Here is an example, where a local branch (orange) is ahead of a remote branch (blue) by two commits.

image.png.c16ef8ac2dcbe9a7836c1d7fae7d7e07.png

Pushing these changes will forward the remote branch to the same commit.

image.png.31f3e6db9207def50b219c7696c50a6b.png

Of course this also works the other way around, in which case you need to pull changes from the remote repository.

Edited by LogMAN
Link to comment

The thing I still find a bit strange is how it is possible for the remote and local branches to be totally different (even different names). I totally get that the local branch can be out of sync if you have not done a push/pull to the server, the thing that seems weird to me is that the local can have a totally different structure. This is just something I need to get used to.

Link to comment
17 hours ago, Neil Pate said:

The thing I still find a bit strange is how it is possible for the remote and local branches to be totally different (even different names).

The common denominator in this case are the commits, each of which is uniquely identifiable by its commit hash.

image.png.2fe57e649e3c8b20cccb5897f3e4876a.png

In ".git/objects" you'll find all commits. When you push or pull a repository, these are the objects that get exchanged.

A branch simply points to one of these commits. If you know the commit id, you can create a branch for it.

In ".git/refs/heads" you'll find all local branches.

In ".git/refs/remotes/<remote>/" you'll find all remote branches (execute 'git fetch <remote>'  to update the list).

Finally, there is a file ".git/config" that specifies which local branch tracks which remote branch. In this example, local branch "main" tracks remote branch "origin/main":

[branch "main"]
	remote = origin
	merge = refs/heads/main

As you already discovered, it is possible to have different names for local and remote branches. This, however, is typically considered bad practice unless you have multiple remotes with the same branch name, in which case a typical approach is to prefix the local branch with the name of the remote (i.e. "origin_main", "coworker_main", ...). A general rule of thumb is to avoid this situation whenever possible.

17 hours ago, Neil Pate said:

I totally get that the local branch can be out of sync if you have not done a push/pull to the server, the thing that seems weird to me is that the local can have a totally different structure. This is just something I need to get used to.

If a local branch does not track a remote branch, it won't get pushed to the remote. This is typically used for private feature/test/throwaway branches. Pretty useful in my opinion, but it also took me a while to wrap my head around this.

Of course you can always push your local branches to the remote with 'git push -u <remote> <branch-name>'.

Link to comment
21 hours ago, Neil Pate said:

The thing I still find a bit strange is how it is possible for the remote and local branches to be totally different (even different names)..... the thing that seems weird to me is that the local can have a totally different structure.

I'm not sure what you mean by "totally different structure". Could you elaborate? Is it captured in the illustration below?

git-dist-sample.png.11d085886b1faea2468ac6c652a1b7f7.png

Alice and Bob clone the same repo and checked out the "master" branch. Bob doesn't like master/slave terminology so he renamed his local branch to "main".

Alice and Bob each want to implement a new feature, so they each created local feature branches.

  • On Alice's PC, "master" tracks "origin/master". "featureA" doesn't track anything.
  • On Bob's PC, "main" tracks "origin/master". "featureB" doesn't track anything.
Link to comment

I guess what I mean is I find it strange that people would even have local branches that are not pushed to the server. Maybe I am just paranoid about my house burning down, my computer getting stolen of my hard drive dying. For me one of big benefits of cloud based VCS is that I almost always have an up-to-date geographically distributed copy of my code.

Link to comment
6 hours ago, Neil Pate said:

I guess what I mean is I find it strange that people would even have local branches that are not pushed to the server. Maybe I am just paranoid about my house burning down, my computer getting stolen of my hard drive dying. For me one of big benefits of cloud based VCS is that I almost always have an up-to-date geographically distributed copy of my code.

Depends on what the server's role is, right?

  • If the server is my cloud backup, then yes I should push all local branches to the server all the time.
  • If the server is hosting a large open-source project that I'm contributing to, then I'm usually not allowed to push my changes to the server until I've finished everything.
  • If the server is hosting my public project releases, then I keep my WIPs and experiments local, and I only push "polished" (possibly squashed/amended) commits.

 

That last scenario minimizes low-quality commits like "Fix typo in previous commit" that make commit history difficult to read and bloat the repository size -- this is especially important with LabVIEW, where each VI change could potentially increase the repo size by 100s of KB, leading to multi-GB repositories very quickly.

  • Like 1
Link to comment
10 hours ago, Neil Pate said:

I guess what I mean is I find it strange that people would even have local branches that are not pushed to the server.

A few years ago I worked on a project that required private API keys. To make things easier, I simply created a private branch that had my keys hardcoded. This is one example of a branch that I certainly didn't want to push to a public server. At the same time it allowed me to regularly merge from master at no cost.

4 hours ago, JKSH said:

Maybe I am just paranoid about my house burning down, my computer getting stolen of my hard drive dying. For me one of big benefits of cloud based VCS is that I almost always have an up-to-date geographically distributed copy of my code.

You could create a custom git hook to push local changes on every commit but you are probably better of with a different VCS.

Link to comment
2 minutes ago, LogMAN said:

You could create a custom git hook to push local changes on every commit but you are probably better of with a different VCS.

I am not *that* paranoid, but certainly I like to push my work at the end of each day. I am not actually anti-git, it is just taking me a while to get used to its best practices and nuances. 

 

  • Haha 1
Link to comment
2 minutes ago, Neil Pate said:

I am not *that* paranoid, but certainly I like to push my work at the end of each day. I am not actually anti-git, it is just taking me a while to get used to its best practices and nuances. 

I should have put a smiley at the end of my sentence 😅

  • Haha 1
Link to comment

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Unfortunately, your content contains terms that we do not allow. Please edit your content to remove the highlighted words below.
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...

Important Information

By using this site, you agree to our Terms of Use.