views:

570

answers:

2

Git has a much-touted(?) octopus-merge capability that can merge many heads into one.

But is there something that would do just the opposite, make several simultaneous branches out of one node?

Let's assume that I have a bunch of code for a project, and I just started using Git. Some of the features are complete in that project, others are still work-in-progress. What I'd want is to get those unfinished features moved into their own respective and separate branch, and have the master as 'complete' as possible, with no unfinished code.

Now, I could of course do all of this in single steps: Create a "unfinished feature #1" branch, and delete the files from the master that are specific to that feature. Then I'd re-branch the master into "unfinished feature #2" and again remove feature #2 specific files from the master, but also from the first branch. And thus the workload increases for each split I do.

Is there something that would help me in such a scenario?

A: 

Since you just started using Git, it would be easier to start again and only commit your 'complete' code to the Master branch. Then checkout a new branch from the master for a feature and commit that 'unfinished' feature code on its own branch. Repeat for each feature branch.

You have to partition the code into features and 'complete' anyway, so use that to set up your repository.

Paul
+5  A: 

Side note: the octopus merge and the octopus branchpoint scenarios are very different. Please remember that pointers in DAG (directed acyclic graph) of commits point from child (newer commit) to parent or parents. So in the case of octopus merge you have commit (commit object) which has more than two parents; in the case of "octopus branchpoint" you simply have a few commits pointing to the same commit as its parent.

octopus merge:

1 <---- M
2 <----/ |
3 <------|

octopus branchpoint:

P <----- 1
^-------- 2
^-------- 3

So I think naming of this question is simply wrong


The answer

Now, if what you want to do is to split modifications in your working area between different branches, to put each feature in separate topic branch, you can make use of explicit staging area (aka index) in Git.

Let's assume that you modified two files, 'a' and 'b', and you want modification to file 'a' to go to branch 'a', and modification in file 'b' to go to branch 'b'. Let's assume that the branch you are currently on, the branching point you want to be base of many branches you want to create, is named 'master'.

First, lets create branch 'a'

$ git checkout -b a master

Git reply with:

M       a
M       b
Switched to a new branch "a"

This means that the files 'a' and 'b' are modified with respect to the point you based branch 'a' on (the 'master' branch). Later I would simply put git response below commandline invocation.
Let us add contents of file 'a' to staging area (index)

$ git add a

Note that if you want to add only some subset of changes in file 'a' to branch 'a', you could use "git add --interactive" or "git gui" to do per-hunk addition of changes to the staging area and other such manipulations.

Now we commit changes to branch 'a'

$ git commit
Created commit 35d0061: Commit description...
 1 files changed, 1 insertions(+), 0 deletions(-)

Note that we didn't use '-a' option to git-commit!
By the way, if you want to test changes before comitting from staging area, you can use "git stash save --keep-index" to get working area to the state you are to commit using "git commit", test changes, then go back to previous state using "git stash pop --index" (or "git stash pop"; I don't remember which one do you need here).

Now we create the other branch, branch 'b', based on branch 'master'

$ git checkout -b b master
M       b
Switched to a new branch "b"

You can easily see that the changes you have left for branch 'b' (the changes you didn't commit to branch 'a') goes to newly created branch 'b'. No need to delete files, or remove changes. No need to know what is in other branches. Everything automatic.
Once again, add contents of file 'b' to staging area (index), and commit on branch b:

$ git add b
$ git commit

You can repeat this as often as necessary, and it doesn't get harder with the new branch.

HTH

Jakub Narębski
Re naming: reversing the arrows on one of your pictures gives the other. I'd say that *by analogy*, calling this "octopus" is "reasonable if misleading" rather than "simply wrong".
A. Rex
But the name "octopus" is here because commit has more than two 'legs' (parents). Branching point doesn't _have_ multiple branches. And you cannot revert arrows: pointers are in one specific direction, not other.
Jakub Narębski