0

I'm using an automated build system Bitrise in combination with Github. When I do a pull request, it runs tests to make sure the new code is OK. If not, as when too people step on each others' toes, this system falls apart. Bitrise will only build code based on a branch name, not a commit hash. So when I do the merges that are required e.g. when a merge conflict breaks the build, I try to commit the fix but the HEAD is detached and I cannot get the branch name to point to HEAD. Not even hard reset is working. So Bitrise continues to fail to build.

Does anyone know a good way to point a branch to a specific commit hash?

  • If I understand you right, have you tried removing the branch and recreating it at the commit hash you need it to be? `git checkout `, `git branch -D `, `git checkout -b `. – miqh Jul 29 '19 at 23:46

1 Answers1

3

First, once you have a detached HEAD, it just keeps being a detached HEAD regardless of any git reset operations. Using git reset, you don't reconnect it, you simply move it about, when it's in this mode.

You may use git checkout branch to attach HEAD to the given branch name at the same time as also checking out the tip commit of branch. Of course, this has no effect on which commit hash ID that particular branch-name names.

It's not clear how you got into detached HEAD mode in the first place, as git merge does not detach HEAD from its current branch if it is on one, nor attach HEAD to a branch if it's detached. The git checkout command will go into detached HEAD mode in many cases though:

  • if you use --detach to force that, or
  • if you use a tag name to specify a commit, or
  • if you use a remote-tracking name like origin/master to specify a commit, or
  • if you use a raw commit hash ID to specify a commit

for instance. (This is not a complete list, it's just a representative sample of things that result in detached HEAD mode.)

If you want to create a new branch name, and make it point to some existing commit, you can:

  • use git branch name hash to create the branch name, pointing to the given commit, but not actually run git checkout on the new name, or
  • use git checkout -b name hash to create the branch name, pointing to the given commit, and check it out and switch to that branch, all in one go.

Again, this is not meant as a complete list of ways to do this, but it is a good representative sample. Note that in all of these cases, we are creating a new name for some existing commit. (Use git log, perhaps with --all --decorate --oneline --graph for instance, to see a list of available commits and their corresponding hash IDs.) There is no requirement that any given commit have a branch name—many commits have no name, just a hash ID—but at the same time, one commit can have dozens of branch names, if you want. The names are really very unimportant to Git: what matters are the hash IDs. Software that demands a name, and won't accept a hash ID, is generally being rather unkind and non-Git-like.1

If you want to force some existing branch name to identify some commit other than the one that it currently identifies, you can:

  • use git branch -f, if it's not the current branch name, or
  • use git reset (with any of --soft, --mixed, or --hard) if it is the current branch name, or
  • use git checkout -B name [hash] to make it the current name (attaching HEAD if needed) and also move the name to either the given hash, or to the current (HEAD) commit if you don't supply a hash ID.

Again, these are representative sample commands, not a full list of every possible one. These are all slightly (or more than slightly) more dangerous than just creating a new name that points to some existing commit. In particular:

  • Forcing a branch name to "forget" some previous commit, and remember some new one, may, depending on a lot of stuff we haven't really covered here, cause your Git to lose easy access to some commit(s) that it previously found through the previous hash ID stored in the name. They can be gotten back for a while (via reflog searching), but not forever.

  • git reset with --mixed or --hard overwrites the index and (with --hard) work-tree contents, which are not frozen-for-as-long-as-you-can-find-the-commit and therefore may be impossible to get back,


1There is a good excuse to demand a name if the software is going to use git fetch and/or git push, or create new commits. That's because git fetch and git push have your Git call up another Git, and exchange commits and names, so these two commands may depend on having a name. The git commit command, when it creates a new commit, writes the new commit's hash ID into the current branch name, or directly into HEAD in the detached HEAD mode, so again there's a reason to want—but not require—a branch name.

torek
  • 448,244
  • 59
  • 642
  • 775