Moving Commits Between Branches - UnosquareBelfast/AdminCore GitHub Wiki

Cherry Picking and Git Log

There will come a time in every developer's life where they've made some commits on the wrong branch. Trying to salvage this can be a pretty intimidating process, but it doesn't need to be with git cherry-pick™️

git cherry-pick allows us to take any commit from any branch and apply it to our current branch. We can get a list of commits in our current branch by utilising the git log command. The following image shows the git log command being run on an example develop branch and then on an example feat1 branch.

As you can see, commits are listed alongside a commit hash. We can use this hash to uniquely identify commits across any branch in our repo. You may also have noticed that our feat1 branch contains commits which should really be on a feat2 branch. But how do we get them there? Cherry picking!

# Get a list of commits on feat1 branch
git log

# Create a new destination branch for the desired commits
git checkout develop
git checkout -b feat2

# Cherry pick the desired commit hashes into the feat2 branch
# It's a good idea to do this in order of oldest to newest commit
git cherry-pick d114b83c9276604404fedf735089403f50c55be9
git cherry-pick 389102e2b0bada47c2351fad150cef823627827f

Once we've ran the above commands, the output of running git log should resemble the following

Now our feat2 branch contains only the commits that we cherry-picked from feat1! But we now need to clean up the feat1 branch and leave it as if our work was never there. We could do this in one of two ways

Reverting

Using git revert we can create a new commit which reverts a previous commit. This is a good approach to use when you have published your commits to the repo and want to preserve the history.

# Checkout feat1
git checkout feat1

# Get a list of commits
git log

# Revert commits that we no longer want in the branch
# It's a good idea to do this in order of newest to oldest commit
git revert 389102e2b0bada47c2351fad150cef823627827f
git revert d114b83c9276604404fedf735089403f50c55be9

# Push our fix to the repo
git push

Resetting

Using git reset we can reset the branch to a previous commit. This is a good approach to use when you haven't published your commits to the repo or if preserving the history isn't a concern.

# Checkout feat1
git checkout feat1

# Reset back to the desired commit
# The --hard flag ignores any changes made during the reset
git reset 0ff593dd112511fbe7bcc300aec3e445980938d7 --hard

# If you've published your erroneous commits to the repo and 
# are feeling brave you can force-push your changes up to repo.
# 🚨Please be careful when force-pushing in any situation 🚨
git push -f

Your repo should now be in a state where the feat1 branch contains the one commit relating to feat1, and the feat2 branch contains the two commits relating to feat2. In a real scenario this would allow us to create clean PRs that contain changes pertaining only to each individual feature and nothing else.

Summary

This was a very straightforward example scenario, and the commands used were used in their most basic form. Git is a very powerful tool that provides a variety of ways to solve a problem like this - as well as more efficient and concise ways of utilising the above commands - but hopefully this guide showed that, while Git might be a powerful tool, it doesn't need to be an intimidating one.

While you're here, check out my Soundcloud at https://soundcloud.com/bgribz