1052

To move the branch pointer of a checked out branch, one can use the git reset --hard command. But how to move the branch pointer of a not-checked out branch to point at a different commit (keeping all other stuff like tracked remote branch)?

2
  • 18
    Sounds like all you wanted to do is a branch from a different commit than the one it is created from now. If my understanding is correct, then why don't you simply create a new branch from the commit you want to create it from using git branch <branch-name> <SHA-1-of-the-commit> and dump the old branch?
    – yasouser
    Commented Mar 29, 2011 at 20:31
  • 17
    @yasouser - I am not sure whatever dumping "master" branch is a good idea. Commented Mar 24, 2013 at 11:49

11 Answers 11

1426
git branch --force <branch-name> [<new-tip-commit>]

If new-tip-commit is omitted, it defaults to the current commit.

new-tip-commit can be a branch name (e.g., master, origin/master).

8
  • 21
    This is a better answer since it handles the 99% case and actually conforms to the documentation. git help branch says " -f, --force Reset <branchname> to <startpoint> if <branchname> exists already. Without -f git branch refuses to change an existing branch." Commented Dec 5, 2012 at 18:22
  • 1
    Very useful if you want to change where another branch is pointing without checking it out.
    – Tim Kist
    Commented Mar 11, 2014 at 9:58
  • 45
    This won't work if the branch you're trying to move is your current branch (HEAD points to it). Commented Apr 30, 2015 at 1:02
  • 2
    What is 'new-tip-commit'? Commented May 30, 2018 at 9:12
  • 2
    This seems to have a side-effect. If your new-tip-commit is a remote branch, it is also set as the upstream for your branch-name. Is there a way around this?
    – PeterG
    Commented Oct 23, 2018 at 12:21
636

You can do it for arbitrary refs. This is how to move a branch pointer:

git update-ref -m "reset: Reset <branch> to <new commit>" refs/heads/<branch> <commit>

where -m adds a message to the reflog for the branch.

The general form is

git update-ref -m "reset: Reset <branch> to <new commit>" <ref> <commit>

You can pick nits about the reflog message if you like - I believe the branch -f one is different from the reset --hard one, and this isn't exactly either of them.

13
  • 46
    Where is the message good for? Where is it stored and how to read it later?
    – Mot
    Commented Mar 21, 2012 at 12:05
  • 4
    NOTE: This does not work on bare repositories. On bare repositories, you have to use 'git branch -f master <commit>' to update the branch (see the answer below). Commented Sep 30, 2012 at 10:13
  • 58
    If, like me, you accidentally use <branch> instead of refs/heads/<branch>, you'll end up with a new file in your .git directory at .git/<branch>, and you'll get messages like "refname 'master' is ambiguous" when you try to work with it. You can delete the file from your .git directory to fix. Commented Jun 6, 2013 at 18:02
  • 56
    It has not been explained to satisfaction why this is any better than git branch -f. To be specific, this method appears to be: (A) harder to use (B) harder to remember, and (C) more dangerous
    – Steven Lu
    Commented Feb 18, 2015 at 10:17
  • 14
    "what exactly is meant by arbitrary refs" - Branches are not the only kind of ref that points to a commit. There are tags, and you can also create arbitrary refs/whatevs/myref style refs yourself that are neither branches nor tags. I believe that also answers Steven Lu's question about what this might be "better". I agree branch -f is simplest if you are working with branches.
    – Adam A
    Commented Apr 2, 2015 at 12:25
163

You can also pass git reset --hard a commit reference.

For example:

git checkout branch-name
git reset --hard new-tip-commit

I find I do something like this semi-frequently:

Assuming this history

$ git log --decorate --oneline --graph
* 3daed46 (HEAD, master) New thing I shouldn't have committed to master
* a0d9687 This is the commit that I actually want to be master

# Backup my latest commit to a wip branch
$ git branch wip_doing_stuff

# Ditch that commit on this branch
$ git reset --hard HEAD^

# Now my changes are in a new branch
$ git log --decorate --oneline --graph
* 3daed46 (wip_doing_stuff) New thing I shouldn't have committed to master
* a0d9687 (HEAD, master) This is the commit that I actually want to be master
7
  • 13
    This is fine if your working tree is clean. If you have lots of staged or unstaged changes, it's probably better to do git update-ref as discussed above. Commented Apr 8, 2014 at 4:35
  • 34
    Did you noticed that your “answer” does not add anything which is not part of the question already?? – OP said: if it is checked out... you can use git reset --hard ... No need to repeat it here! :-( Commented Apr 20, 2015 at 11:11
  • 8
    @Robert: I disagree. The question didn't say how to use it and this does. It was nice not to have to go look for that how.
    – Wilson F
    Commented Aug 11, 2015 at 18:57
  • 12
    @WilsonF, maybe it was nice for you to find this here, but it is not answering the question at all. Maybe it is the answer of some other question, but here it is wrong. Commented Aug 12, 2015 at 7:52
  • 4
    I think this should maybe have been a comment on the question, not an answer. (Or maybe it was answering an earlier version of the question?) Commented May 7, 2020 at 15:21
72

Just to enrich the discussion, if you want to move myBranch branch to your current commit, just omit the second argument after -f

Example:

git branch -f myBranch


I generally do this when I rebase while in a Detached HEAD state :)

28

Git 2.23.0 introduced the git-switch command that can also be used to do this.

git switch -C <branch-name> [<start-point>]

The -C (uppercase C) option indicates that if <branch-name> already exists, it will reset it to <start-point>.

With -c (lowercase C) it will try to create a new branch but fails if one already exists.

<start-point> can be a hash, a tag, or another branch name.

4
  • 1
    I like this idea, but as of git version 2.35.1 ... git switch --help | egrep -i EXPERIMENTAL said THIS COMMAND IS EXPERIMENTAL. THE BEHAVIOR MAY CHANGE.
    – MarkHu
    Commented Apr 28, 2022 at 18:18
  • The git switch command has been experimental from when it was introduced in version 2.23.0. See this from the Git Blog in August 2019 github.blog/2019-08-16-highlights-from-git-2-23
    – alondono
    Commented Apr 28, 2022 at 23:09
  • I'd say that it is normal for a new command to be introduced first as experimental. It simply means some of the options or flags might change, or others might be added or improved. The -c|-C flag behaviour discussed here has not changed since the command was introduced in August 2019.
    – alondono
    Commented Apr 28, 2022 at 23:21
  • 1
    Best answer for my specific usecase. Note that this checks the branch out after it reseted it to <start-point>. This is very useful for grapping another branch laying around somewhere, reset it to the current HEAD and start working on it. Commented yesterday
14

If you want to move a non-checked out branch to another commit, the easiest way is running the git branch command with -f option, which determines where the branch HEAD should be pointing to:

git branch -f <branch-name> (<sha1-commit-hash> or <branch-name>)

For example if you want your local develop branch to track the remote (origin) develop branch:

git branch -f develop origin/develop

Be careful as this won't work if the branch you are trying to move is your current branch. To move a branch pointer, run the following command:

git update-ref -m "reset: Reset <branch-name> to <sha1-commit-hash>" \
  refs/heads/<branch-name> <sha1-commit-hash>`

The git update-ref command updates the object name stored in a ref safely.

Hope, my answer helped you.The source of information is this snippet.

13

In gitk --all:

  • right click on the commit you want
  • -> create new branch
  • enter the name of an existing branch
  • press return on the dialog that confirms replacing the old branch of that name.

Beware that re-creating instead of modifying the existing branch will lose tracking-branch information. (This is generally not a problem for simple use-cases where there's only one remote and your local branch has the same name as the corresponding branch in the remote. See comments for more details, thanks @mbdevpl for pointing out this downside.)

It would be cool if gitk had a feature where the dialog box had 3 options: overwrite, modify existing, or cancel.


Even if you're normally a command-line junkie like myself, git gui and gitk are quite nicely designed for the subset of git usage they allow. I highly recommend using them for what they're good at (i.e. selectively staging hunks into/out of the index in git gui, and also just committing. (ctrl-s to add a signed-off: line, ctrl-enter to commit.)

gitk is great for keeping track of a few branches while you sort out your changes into a nice patch series to submit upstream, or anything else where you need to keep track of what you're in the middle of with multiple branches.

I don't even have a graphical file browser open, but I love gitk/git gui.

7
  • 1
    So easy! I may have just converted from gitg to gitk. Commented Jun 3, 2016 at 19:58
  • This way, however, the tracking branch information is lost.
    – mbdevpl
    Commented Jun 14, 2017 at 8:23
  • @mbdevpl: I'm not really a git expert. I think I understand what you mean, but not the implications. I've used this fairly often, and still been able to push those branches to branches of the same name on a remote. What does the association between a branch and its remote-tracking branch do for you? Commented Jun 14, 2017 at 16:41
  • @mbdevpl: does that mostly only matter when your local branch has a different name from the remote branch it's tracking? Commented Jun 14, 2017 at 16:50
  • 1
    @PeterCordes Ineed, when branch names don't match it matters. Also when there is more than one remote. Also when you're using git prompt to display branch status, it'll show commit distance to your tracking branch (if it's set). Also, git status output is affected. Additionally, in some cases git fetch and git push won't work without specifying remote explicitly if you don't set the tracking branch. I don't know about all the cases, but for me the general rule of thumb is that for convenience and speed of work, it's better to have tracking branches in order.
    – mbdevpl
    Commented Jun 15, 2017 at 10:53
9

The recommended solution git branch -f branch-pointer-to-move new-pointer in TortoiseGit:

  • "Git Show log"
  • Check "All Branches"
  • On the line you want the branch pointer to move to (new-pointer):
    • Right click, "Create Branch at this version"
    • Beside "Branch", enter the name of the branch to move (branch-pointer-to-move)
    • Under "Base On", check that the new pointer is correct
    • Check "Force"
    • Ok

enter image description here

enter image description here

0
8

Honestly, I'm surprised how nobody thought about the git push command:

git push -f . <destination>:<branch>

The dot ( . ) refers the local repository, and you may need the -f option because the destination could be "behind its remote counterpart".

Although this command is used to save your changes in your server, the result is exactly the same as if moving the remote branch (<branch>) to the same commit as the local branch (<destination>)

1
  • 2
    You can also do this without -f to avoid clobbering anything local; for instance, git fetch origin && git push . origin/develop:develop is a no-checkout-needed fail-fast version of git checkout develop && git pull --ff-only
    – btown
    Commented Mar 8, 2020 at 19:59
5

Open the file .git/refs/heads/<your_branch_name>, and change the hash stored there to the one where you want to move the head of your branch. Just edit and save the file with any text editor. Just make sure that the branch to modify is not the current active one.

Disclaimer: Probably not an advisable way to do it, but gets the job done.

6
  • 4
    Not sure whether this is the chaotic or evil way to do it. 🤔 😉 Commented May 7, 2020 at 15:26
  • 1
    @KeithRussell may be both :P Commented May 7, 2020 at 16:43
  • 3
    @KeithRussell, @G Merely chaotic, unless you're messing with a public repo! :-) In one sense, this is a supported way to do it, since the git documentation describes its inner workings in great detail. Being able to understand which files are updated how by, e.g. git commit is the most compelling reason to use git instead of mercurial.
    – jpaugh
    Commented Jul 2, 2020 at 17:21
  • @jpaugh, Question is how to ensure this operation is atomic?
    – Pacerier
    Commented Jun 15, 2023 at 2:28
  • @GuillermoGutiérrez, Is there a way to do this via the browser? (for github)
    – Pacerier
    Commented Jun 15, 2023 at 2:28
-4

For the checked out branch, in the case the commit you want to point to is ahead of the current branch (which should be the case unless you want to undo the last commits of the current branch), you can simply do:

git merge --ff-only <commit>

This makes a softer alternative to git reset --hard, and will fail if you are not in the case described above.

To do the same thing for a non checked out branch, the equivalent would be:

git push . <commit>:<branch>
5
  • Question asked about what to do if the branch is not checked out. Commented May 7, 2020 at 15:24
  • Oops, I missed that point. In that case you could do git push . <commit>:<branch> as already suggested.
    – Jean Paul
    Commented May 7, 2020 at 23:14
  • 1
    This doesn't answer the question, because a merge creates a new commit (and a new state of affairs). It doesn't simply update the branch pointer, unless you do a git merge --ff-only, and then only if there are no conflicts.
    – jpaugh
    Commented Jul 2, 2020 at 17:11
  • 1
    @jpaugh That's why I said in the case the commit you want to point to is ahead (I could also have precised and not behind). Yes you can use the --ff-only option if you want to be sure, but that option does not alter the way the merge is done, it just prevents non fast forward merges to be done. Also, if the merge is not fast forward, you can refuse the commit and cancel the merge with git merge --abort.
    – Jean Paul
    Commented Jul 3, 2020 at 9:50
  • @JeanPaul You're clearly an expert with git, but many of your readers won't be. A novice needs to know not only which command to use, but in what context. Your last comment helps tremendously with that. But to answer the OP's question with git merge would require a few more commands to protect both the starting branch and the working tree. git stash; git checkout <branch>; git merge --ff-only <commit>; git checkout <starting-branch>; git pop
    – jpaugh
    Commented Jul 6, 2020 at 15:04

Not the answer you're looking for? Browse other questions tagged or ask your own question.