user4918296
user4918296

Reputation:

GIT: Separate two projects in one repository

Suppose I have two unrelated projects in one git repository. Each project resides in its own folder but both folders are in the master branch. The git repo structure looks like this:

Folder structure:
/path/to/projectfolders/
|-  .git
|-  project1
|-  project2

Branch master:
p1_commit1 <- p2_commit1 <- mixed_commit <- p1_commit2 <- p2_commit3 <- master

mixed_commit means that there were additions/modifications in project1 as well as project2. I would like to put the two projects in two separate branches - p1 and p2 - that do not share any history, so that the repo will look like this:

Branch p1:
p1_commit1 <- p1_mixed_commit <- p1_commit2 <- p1

Branch p2:
p2_commit1 <- p2_mixed_commit <- p2_commit3 <- p2

The strategy I have in mind is to first create the two branches p1 and p2. Then checkout p1 and delete every commit that is related to project2. Afterwards checkout p2 and delete every commit that is related to project1.

Finally, delete the master branch.

Since I am still new to git, I have two questions about this:

  1. Is this a safe strategy or are there any drawbacks that I did not think of?

  2. If the strategy is good, what is the best way to delete the common commit history in each branch? I was thinking of using rebase, and then "simply" only picking the commits that belong to the project on the dedicated branch. Will this be enough to get rid of the unrelated commits of the other project?

PS: Since people have been suggesting it, splitting the repository into two separate repos is not an option. It has to remain one repository.

Upvotes: 1

Views: 606

Answers (1)

user4918296
user4918296

Reputation:

I finally came up with a solution to separate the projects in master into dedicated branches. I will go through the steps that are necessary to separate project 2 into its own branch.

I will assume the following repository and folder structure for this example:

Folder structure:
/path/to/projectfolders/
|-  .git
|-  project1
|-  project2

Branch master:
p1_commit1 <- p2_commit1 <- mixed_commit <- p1_commit2 <- p2_commit3 <- master

mixed_commit means that there were additions/modifications in project1 as well as project2.

Step 1

Checkout master and generate a temporary branch which points to the HEAD of master:

git checkout master
git checkout -b tmp

Step 2

Search through the logs to identify which commit contributed to which project. Identify the earliest commit that belongs to the project you want to separate, e.g., for project 2 this would be p2_commit1. Pay also attention to commits like mixed_commit which contributed files to both projects.

git log --stat # write down commit hashes that belong to project 2

Step 3

Check out an orphan branch (name it, e.g., p2 for project 2) of the earliest commit of project 2 and clean it, i.e., remove any files that do not belong to project 2. When git checks out an orphan branch it will have the files that are affected by this commit already staged. This can be easily corrected by deleting the index. Then you can stage only the files that belong to project 2 and commit them

git checkout --orphan p2 <hash of p2_commit1>
rm .git/index # clear index
rm -r project1 # remove any files/folders not related to project 2
git add project2
git commit -m "Created branch for project 2"

The newly created branch now contains the earliest commit of project 2.

Step 4

Switch back to the temporary branch. Then interactively rebase the tmp branch onto p2.

git checkout tmp
git rebase -i p2

This is how the interactive rebase may look like when the editor is launched. Notice, that p2_commit1 is not offered, since it is already in branch p2.

pick hash1 p1_commit1
pick hash2 mixed_commit
pick hash3 p1_commit2
pick hash4 p2_commit3

Pick only those commits (the ones you wrote down at step 2) that belong to project 2. You must manually edit the commits that contain files for both projects. So your final rebase file may look like this:

edit hash2 mixed_commit
pick hash4 p2_commit3

Save the changes and close the editor. The rebase will be interrupted whenever it encounters a commit that is marked as edit. Do what needs to be done to remove the files that do not belong to project 2 and amend the comit. The procedure in this example scenario may look like

# git rm -r project1
# git commit --amend

When you are satisfied with the result continue the rebasing process and check the log to verify that all commits have been correctly rebased.

git rebase --continue
git log --stat

Step 5

Currently, we are still on the temporary branch. Checkout branch p2 and check the log.

git checkout p2
git log --stat

It contains only the initial commit from step 3. The rest of the related commits reside on the temporary branch, so we will have to merge:

git merge tmp

If everything went fine in step 4 then the last command will result in a fast-forward merge.

We finally have a dedicated branch for project 2 which contains only the commits that contribute files for project2. The temporary branch is now no longer needed.

Step 6

This is a final clean-up step. Simply remove the now obsolete temporary branch.

git branch -D tmp

Done.

Now you can checkout master

git checkout master

and repeat step 1 through step 6 in order to separate the remaining projects in your repository.

Upvotes: 1

Related Questions