363

In Git, I understand that a branch is a pointer to a commit.

How do I make a specific branch point to a specific commit? Say I want to make master point at 1258f0d0aae..., how do I do that?

c00kiemon5ter
  • 16,994
  • 7
  • 46
  • 48
Ram Rachum
  • 84,019
  • 84
  • 236
  • 374

4 Answers4

495

You can make master point at 1258f0d0aae this way:

git checkout master
git reset --hard 1258f0d0aae

But you have to be careful about doing this. It may well rewrite the history of that branch. That would create problems if you have published it and other people are working on the branch.

Also, the git reset --hard command will throw away any uncommitted changes (i.e. those just in your working tree or the index).

You can also force an update to a branch with:

git branch -f master 1258f0d0aae

... but git won't let you do that if you're on master at the time.

mit
  • 11,083
  • 11
  • 50
  • 74
Mark Longair
  • 446,582
  • 72
  • 411
  • 327
  • 5
    you don't need --hard – ahnbizcad Feb 05 '20 at 03:56
  • 7
    `git branch -f` is useful. It's nice that I can change the branch without checking it out first. – remcycles Aug 02 '21 at 02:42
  • 1
    `git branch -f ` by default sets `` to point at `` and if `` is also a branch, it sets remote tracking branch to `` to branch ``. To avoid adjustment of remote tracking branch, use extra option `--no-track`: `git branch --no-track -f ` – czerny Apr 11 '22 at 17:27
  • I have to look this up about once a month. Really unintuitive command. – Dominik Apr 21 '23 at 09:59
155

If you are currently not on branch master, that's super easy:

git branch -f master 1258f0d0aae

This does exactly what you want: It points master at the given commit, and does nothing else.

If you are currently on master, you need to get into detached head state first. I'd recommend the following two command sequence:

git checkout 1258f0d0aae    #detach from master
git branch -f master HEAD   #exactly as above

#optionally reattach to master
git checkout master

Be aware, though, that any explicit manipulation of where a branch points has the potential to leave behind commits that are no longer reachable by any branches, and thus become object to garbage collection. So, think before you type git branch -f!


This method is better than the git reset --hard approach, as it does not destroy anything in the index or working directory.

cmaster - reinstate monica
  • 38,891
  • 9
  • 62
  • 106
  • 9
    This is always what I want when I search for this, and everyone is pushing `reset --hard`--I almost lost work doing that (thankfully had the stash still). Thank you for the straightforward, "I want to make no other changes" solution. – msouth Jul 21 '21 at 18:46
  • It does lose the detached commit. It's not deleted, but you have to find it in reflog. – Justin Trevein Jan 28 '22 at 14:32
  • 1
    @JustinTrevein That's exactly the point of the paragraph below the second code block. Also, the method only loses the detached commit if it's not reachable from some other branch, it's not unconditionally lost. But I'll take the hint that my warning was not sufficiently visible and bold up the "think before ..." part. – cmaster - reinstate monica Mar 10 '22 at 06:10
  • Just go `git reset` without `--hard`, then? – Gauthier Nov 18 '22 at 21:38
  • @Gauthier Nope. `git reset` without a mode is equivalent to `git reset --mixed`, and this will reset the index. I.e. you'll loose any work you may have done for a partial commit. The `git checkout`/`git branch -f`/`git checkout` sequence has the benefit that it's only the `git checkout` that ever touches your files, and that's generally relatively safe to perform. Much safer than simply forgetting the old index. – cmaster - reinstate monica Nov 18 '22 at 21:56
  • @cmaster-reinstatemonica `git reset --soft` then? – Gauthier Nov 21 '22 at 11:42
  • @Gauthier Again, no. `git reset --soft` does not rebase your current changes onto the new `HEAD` as `git checkout` would do. Instead, it changes the reference point from which it calculates differences, so that you will see all the differences from the new `HEAD` to the old `HEAD` as uncommitted changes. Most definitely not what you want. `git reset` simply is not the right tool for this operation in my experience. `--hard` is too dangerous, `--soft` lacks intelligence, and `--mixed` is both of these combined. `git checkout` is intelligent, and `git branch -f` is minimally invasive. – cmaster - reinstate monica Nov 21 '22 at 19:40
  • I must have looked up this command dozens of times. Really hard to remember. – Dominik Feb 02 '23 at 12:58
  • Shout-out to `git log develop@{1}` as described here: https://stackoverflow.com/a/60645768/5715151 ; was useful for troubleshooting after I had used `git branch -f`, which turned out to be the easiest way to update the pointer to a branch in a repo in code-commit. It was nice that there were troubleshooting tools even after I had done the thing that everyone warned against. – Cognitiaclaeves Jun 08 '23 at 20:52
  • This should be the accepted answer. It does what the question asks without the side effects of `git reset --hard` (deleting your uncommitted changes!) – whoKnows Jul 21 '23 at 16:01
47

git branch -f <branchname> <commit>

I go with Mark Longair's solution and comments and recommend anyone reads those before acting, but I'd suggest the emphasis should be on

git branch -f <branchname> <commit>

Here is a scenario where I have needed to do this.

Scenario

Develop on the wrong branch and hence need to reset it.

Start Okay

Cleanly develop and release some software.

So far so good

Develop on wrong branch

Mistake: Accidentally stay on the release branch while developing further.

After a mistake

Realize the mistake

"OH NO! I accidentally developed on the release branch." The workspace is maybe cluttered with half changed files that represent work-in-progress and we really don't want to touch and mess with. We'd just like git to flip a few pointers to keep track of the current state and put that release branch back how it should be.

Create a branch for the development that is up to date holding the work committed so far and switch to it.

git branch development
git checkout development 

Changed to another branch

Correct the branch

Now we are in the problem situation and need its solution! Rectify the mistake (of taking the release branch forward with the development) and put the release branch back how it should be.

Correct the release branch to point back to the last real release.

git branch -f release release2

The release branch is now correct again, like this ...

Corrected

What if I pushed the mistake to a remote?

git push -f <remote> <branch> is well described in another thread, though the word "overwrite" in the title is misleading. Force "git push" to overwrite remote files

Ivan
  • 4,383
  • 36
  • 27
47
git reset --hard 1258f0d0aae

But be careful, if the descendant commits between 1258f0d0aae and HEAD are not referenced in other branches it'll be tedious (but not impossible) to recover them, so you'd better to create a "backup" branch at current HEAD, checkout master, and reset to the commit you want.

Also, be sure that you don't have uncommitted changes before a reset --hard, they will be truly lost (no way to recover).

CharlesB
  • 86,532
  • 28
  • 194
  • 218