164

I have made several commits in the master branch and then merged them to the dev branch.

I want to create a branch from a specific commit in the dev branch, which was first committed in the master branch.

I used the commands:

git checkout dev
git branch  <branch name> <commit id>

However, this creates the branch from the master branch, not the dev branch I expected. The commit id is same in the master branch and dev branch. So, how can I distinguish same commit id in a different branch?

PS: I made an example at GitHub.

I used the commands:

git checkout dev
git branch test 07aeec983bfc17c25f0b0a7c1d47da8e35df7af8

I expect that the test branch contains aa.txt, bb.txt, and cc.txt. However, the test branch only contains aa.txt and cc.txt. It most likely created the branch from the master branch.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
RolandXu
  • 3,566
  • 2
  • 17
  • 23
  • 1
    Unfortunately, the original git repo on github no longer exists which makes this question and the the answers that refer to it less useful – Rondo Mar 13 '22 at 22:20
  • Related: *[How do I create a new Git branch from an old commit?](https://stackoverflow.com/questions/7167645/)* (2011) and *[Branch from a previous commit using Git](https://stackoverflow.com/questions/2816715/)* (2010) – Peter Mortensen May 02 '23 at 22:48

5 Answers5

202

If you are using this form of the branch command (with start point), it does not matter where your HEAD is.

What you are doing:

git checkout dev
git branch test 07aeec983bfc17c25f0b0a7c1d47da8e35df7af8
  • First, you set your HEAD to the branch dev,

  • Second, you start a new branch on commit 07aeec98. There is no bb.txt at this commit (according to your github repo).

If you want to start a new branch at the location you have just checked out, you can either run branch with no start point:

git branch test

or as other have answered, branch and checkout there in one operation:

git checkout -b test

I think that you might be confused by that fact that 07aeec98 is part of the branch dev. It is true that this commit is an ancestor of dev, its changes are needed to reach the latest commit in dev. However, they are other commits that are needed to reach the latest dev, and these are not necessarily in the history of 07aeec98.

8480e8ae (where you added bb.txt) is for example not in the history of 07aeec98. If you branch from 07aeec98, you won't get the changes introduced by 8480e8ae.

In other words: if you merge branch A and branch B into branch C, then create a new branch on a commit of A, you won't get the changes introduced in B.

Same here, you had two parallel branches master and dev, which you merged in dev. Branching out from a commit of master (older than the merge) won't provide you with the changes of dev.


If you want to permanently integrate new changes from master into your feature branches, you should merge master into them and go on. This will create merge commits in your feature branches, though.

If you have not published your feature branches, you can also rebase them on the updated master: git rebase master featureA. Be prepared to solve possible conflicts.

If you want a workflow where you can work on feature branches free of merge commits and still integrate with newer changes in master, I recommend the following:

  • base every new feature branch on a commit of master
  • create a dev branch on a commit of master
  • when you need to see how your feature branch integrates with new changes in master, merge both master and the feature branch into dev.

Do not commit into dev directly, use it only for merging other branches.

For example, if you are working on feature A and B:

a---b---c---d---e---f---g -master
    \       \
     \       \-x -featureB
      \
       \-j---k -featureA

Merge branches into a dev branch to check if they work well with the new master:

a---b---c---d---e---f---g -master
    \       \            \
     \       \            \--x'---k' -dev
      \       \             /    /   
       \       \-x----------    /    -featureB
        \                      /
         \-j---k--------------- -featureA

You can continue working on your feature branches, and keep merging in new changes from both master and feature branches into dev regularly.

a---b---c---d---e---f---g---h---i----- -master
    \       \            \            \
     \       \            \--x'---k'---i'---l' -dev
      \       \             /    /         /
       \       \-x----------    /         /  -featureB
        \                      /         /  
         \-j---k-----------------l------ -featureA

When it is time to integrate the new features, merge the feature branches (not dev!) into master.

Gauthier
  • 40,309
  • 11
  • 63
  • 97
  • thanks. You answer my question. I am wrong in understanding of git branch mode. And do you have any suggestion for my problem. I have the master branch which has many commits timely from others(sync with perforce). I have dev branch I do personal work. I want a branch that contains all commits from master branch and dev branch, then I can easily create branch based this branch, then to start specific working. – RolandXu Dec 14 '11 at 00:52
  • I could not answer in a comment, so I update my answer with suggested workflows. – Gauthier Dec 14 '11 at 09:04
  • Hey -- thanks for the brilliant and thorough answer! Just curious: In the end, why should one `merge the feature branches (not dev!) into master`? – cassi.lup Jan 17 '14 at 09:01
  • There is no real new development in the `dev` branch. You should keep your branches feature specific. `dev` contains only merge commits. It makes more sense to merge all new features to directly `master`, than merging together the features then merging the result into `master`. – Gauthier Jan 20 '14 at 07:49
  • @Gauthier You did not address the question of why. To me it sounds like merging a `dev` with just features `A` `B` and `C` merged into it into `master` is identical to individually merging `A` `B` and `C` into `master`. If not, that challenges my understanding of how git works and I would be very curious as to why! – Steven Lu Jul 17 '17 at 18:58
  • @Steven Lu The content of the file system might probably be the same, but when you merge into dev you create merge commits which don't make much sense in the history (given that you don't fast-forward merge). – Gauthier Jul 17 '17 at 21:55
79

You have the arguments in the wrong order:

git branch <branch-name> <commit>

and for that, it doesn't matter what branch is checked out; it'll do what you say. (If you omit the commit argument, it defaults to creating a branch at the same place as the current one.)

If you want to check out the new branch as you create it:

git checkout -b <branch> <commit>

with the same behavior if you omit the commit argument.

Cascabel
  • 479,068
  • 72
  • 370
  • 318
51

You can do this locally as everyone mentioned using

git checkout -b <branch-name> <sha1-of-commit>

Alternatively, you can do this in GitHub itself, follow the steps:

  1. In the repository, click on the Commits.

  2. on the commit you want to branch from, click on <> to browse the repository at this point in the history.

    Commits history

  3. Click on the Tree: xxxxxx in the upper left. Just type in a new branch name there. Click Create branch xxx as shown below.

    Create a new branch

Now you can fetch the changes from that branch locally and continue from there.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Muhammad Soliman
  • 21,644
  • 6
  • 109
  • 75
13

Try

git checkout <commit hash>
git checkout -b new_branch

The commit should only exist once in your tree, not in two separate branches.

This allows you to check out that specific commit and name it what you will.

ZMorek
  • 679
  • 1
  • 8
  • 24
11

You have to do:

git branch <branch_name> <commit>

(you were interchanging the branch name and commit)

Or you can do:

git checkout -b <branch_name> <commit>

If in place of you use branch name, you get a branch out of tip of the branch.

manojlds
  • 290,304
  • 63
  • 469
  • 417
  • That's not what `HEAD` means. You could say "the tip of the branch" or "the commit the branch points to" instead. – Cascabel Dec 13 '11 at 05:07
  • @Jefromi - To be purists, we can say the branch only, as the branch itself is pointer to, well, the tip of the branch. – manojlds Dec 13 '11 at 05:16