Two separate features were committed onto the same branch. The oldest commit represents one cohesive feature ("Feature 1"). All the subsequent commits represent a second, separate cohesive feature ("Feature 2").
In retrospect, these should have been separate feature branches, but they were all committed to the same branch.
Now: The predictable problem has occurred. The dev is asked to merge Feature 2 into Master, but not Feature 1.
#0 they branch off MASTER, intending to use the branch for feature 2 - calling their new branch "Feature_2".
#1 they forget what branch they're on (feature 2), and make/test/commit/push a load of file changes for "Feature 1" in a single commit.
#2, 3, 4 they then go on to make all the necessary changes for Feature 2, committing and pushing, to the same branch, as they go.
Now - someone asks them to commit feature 2 (commits #2, #3, #4) without feature 1 (commit #1).
#4 they created a new branch and called it, say, "BEFORE_REVERTING_#1"
#5 They Git Revert commit#1 (Via sourcetree's 'reverse changes...' option.)
#6 they merge commit#5 into master.
Final state:
So now they've succeeded in merging #2,3,4 into master, without the code from #1.
Now or later, how do we pull Feature 1 / Commit #1 into Master? (Such that both Features 1 and 2 are in Master, and the history is somewhat decipherable, if not entirely streamlined)
Am I right in saying we can't do it with just merging, because BEFORE_REVERTING_#1 is just a pointer to the same node that was later reverted, and will be fast forwarded, and need to use some other .git feature?
If you happne to know SourceTree UI - Is there an easy way to do this using the SourceTree?
What should the dev have done, instead of the approach in step 4/5, assuming #1-3 had already happened?
Thank you for any help or clarification you can provide!
Now or later, how do we pull Feature 1 / Commit #1 into Master?
Cherry pick it. Essentially this copies the commit.
git checkout master
git cherry-pick <commit id of feature 1>
What should the dev have done, instead of the approach in step 4/5, assuming #1-3 had already happened?
Reverting the commit was fine. But they also could have split the feature branch into two branches.
You had this.
A - B [master]
\
1A - 2A - 2B [feature]
You want this.
2A - 2B [feature]
/
A - B [master]
\
1A [feature1]
First, stick a new branch on 1A.
git branch feature1 1A
A - B [master]
\
1A [feature1]
\
2A - 2B [feature]
Then rebase 2A and 2B on top of master.
git rebase --onto master 1A 2B
2A1 - 2B1 [feature]
/
A - B [master]
\
1A [feature1]
And you're done.
For a more complex untangling, use an interactive rebase to selectively remove commits. For example, if you had...
A - B [master]
\
1A - 2A - 1B - 2B [feature]
And you wanted...
2A - 2B [feature]
/
A - B [master]
\
1A - 1B [feature1]
Make a new branch at feature
.
git checkout feature
git branch feature1
A - B [master]
\
1A - 2A - 1B - 2B [feature]
[feature1]
Then do an interactive rebase on each of them. Remove the offending commits. From feature
remove 1A and 1B. From feature1
remove 2A and 2B.
git checkout feature
git rebase -i master
# delete 1A and 1B
2A - 2B [feature]
/
A - B [master]
\
1A - 2A - 1B - 2B [feature1]
git checkout feature1
git rebase -i master
# delete 2A and 2B
2A - 2B [feature]
/
A - B [master]
\
1A - 1B [feature1]