TheRedCameron
TheRedCameron

Reputation: 171

How to duplicate branch

I have two branches. 'master' and 'testing'.

                ___testing____  
               /
------master--------

I want to continue with the testing branch to add features, but before that, I need to merge the testing branch to master. I want to create a third branch called 'testing2' that is exactly the same as 'testing', but comes from the 'master' branch instead of being a branch off of 'testing'.

                   _____testing___
                  /
---------master----------
                  \____testing2____

As an alternative, I know I can merge the 'testing' branch to 'master' and create two new branches and do my work that way,

                _____testing_____        ____newtest___
               /                 \      /                 
---master-------------------------------------------------
                                        \____continuetest_____

but is there not a way to simply duplicate the branch 'testing'?

Upvotes: 4

Views: 18714

Answers (3)

torek
torek

Reputation: 489035

If you have used other version control systems—especially Mercurial, which really is a lot like Git but with some key differences including this very one here—you might expect commits to remember which branch they were made on.

In Mercurial, they do.

In Git, they don't.

A branch name is nothing more than a label pointing to one commit

In Git, think of a branch name as a sort of yellow sticky note. The note has the name of the branch on it, but it's just loosely attached to the commit itself:

<--o   <--branch

The commit has its own outgoing arrow, which points to the commit's parent commit. This builds up a backwards chain of commits. If we give each commit a single letter name and draw arrows saying who points to whom, we get:

A <- B <- C   <-- branch

Here A is the very first commit ever. It has no parent—it can't have one, so it just doesn't. B is the second commit, and its parent is A, so B points to A. (Literally, B has A's hash ID inside it, as part of B itself.) Likewise, C points to B. The name branch remembers the big ugly hash ID of commit C, so that we don't have to.

To make a new commit:

  1. Git collects a log message from you.
  2. Git writes out the index (aka staging area): whatever you have updated with git add is new, everything else is the same as before.
  3. Git writes out a new commit. The new commit's parent is the current commit (its hash ID). The new commit's log message is the one you wrote; the author and committer of the new commit is you; and the saved tree (source code) for the new commit is the result of writing out the index.
  4. This new commit has a new, unique hash ID, different from every other commit ever made.
  5. Here is the secret of branches: Whatever branch you are on right now, Git puts the new ID into the branch name. So now branch remembers the new commit D we just made:

    A <- B <- C <- D   <-- branch
    

    In effect, Git peels the sticky-note off the old commit and pastes it on the new one.

If you attach multiple names to one commit, and then make a new commit, Git only peels off one sticky-note. So if you make a new name that points to C, and then make new commit D, only the current branch name moves to D, the old one stays with C:

A--B--C     <-- newname
       \
        D   <-- branch

You should now ask how Git knows which label is the current branch!

The answer is HEAD. This is why, if you use git log --decorate, you will see things like:

commit e0688e9... (HEAD -> master, origin/master, origin/HEAD)

This tells me that Git believes the current branch is master, and that there are three names for the current commit e0688e9...: master, origin/master, and origin/HEAD.

Upvotes: 6

adrianbanks
adrianbanks

Reputation: 82994

Branching from testing to create a testing2 branch is equivalent to creating a branch from master that is the same as testing.

For example:

                              ___testing2__
                ___testing___/
               /
------master--------

is logically equivalent to:

                ___testing___
               /
------master--------
               \___testing2__

with the same changes in the testing and testing2 branches. It may not show like that in the log/graph, but it is the same.

Think about it more like:

                X
               /
------master--------

where the commit at X has both branch labels of testing and testing2.

I've just created this structure to give a better view. When creating the testing2 branch, you will get:

starting point

Once you've made some commits on each branch, you will get:

after commits to branches

Upvotes: 2

Kevin
Kevin

Reputation: 607

Merge with master then:

git checkout master
git branch testing2
git pull origin master

Upvotes: 1

Related Questions