Git Cherry Pick

Today, I learned about git cherry-pick. The man page of cherry-pick states that:

Given one existing commit, apply the change the patch introduces, and record a new commit that records it. This requires your working tree to be clean (no modifications from the HEAD commit).

One of the use case I know of is to take a commit from one branch, and apply it on another. Given this,

- a - b - c - d - e - f (master)
            \
              g - h - i (dev)

and if I do this:

git checkout dev
git cherry-pick [SHA-1 hash of commit f]

I will have this:

- a - b - c - d - e - f (master)
            \
              g - h - i - f"(dev)

Now I will have another commit f” with a different SHA-1 hash from commit f.


However, take note that there are consequences of cherry-picking. The history in commit d and commit e will be lost. Consider a simpler tree:

- a - b - c (master)
    \
      d (dev)

Referring to the simple tree above, let’s say we introduce cheese_cake_recipe.txt in commit b with the content:

get_recipe() {
  return "cheese + flour + lime juice"
}

and changes the content of cheese_cake_recipe.txt in commit c into:

get_recipe() {
  return "cheese + flour + milk"
}

later I cherry-pick it from the (dev) branch like this:

git checkout dev
git cherry-pick [SHA-1 hash of commit c]

now I have this:

- a - b - c (master)
    \
      d - c" (dev)

But in commit c”, the content of cheese_cake_recipe.txt will be:

get_recipe() {
  return "cheese + flour + milk"
}

And we never know that lime juice ever exist in the older recipe, now our cheesecake won’t taste as nice and we won’t be able to find out why easily.

So use with care… Here are 2 posts talking about this:

http://stackoverflow.com/questions/880957/pull-all-commits-from-a-branch-push-specified-commits-to-another/881014#881014

http://stackoverflow.com/questions/881092/how-to-merge-a-specific-commit-in-git/881112#881112

Advertisements

Git Checkout

I just want to record down the 2 common usages of git checkout so that I don’t need to refer again next time!

git checkout — <filename>

  • this will overwrite your file with the name <filename> in your working directory with the <filename> from the staging area.

git checkout -f

  • replace all the files in the working directory with files from HEAD
  • clear the staging area to match with HEAD

Git Reset

I always forget about what does git reset do exactly after not using it for a while. So I decided to write it down with diagrams. Below is the usage of git reset with different arguments:

git reset <commit>

  • update HEAD+master to point to <commit> (if HEAD is attached to master)
  • update index to match <commit>
  • working directory(WD) untouched

git reset –soft <commit>

git reset –hard <commit>

git reset — <filename> or git reset HEAD — filename

  • unstage the file name <filename>, in other words, if it is a tracked file, it will revert index’s <filename> to HEAD’s <filename>; if it is not a tracked file, it will simply unstage it.

git reset <commit> — <filename>

  • work the same as the above git reset — <filename>, but instead of updating with HEAD’s <filename>, it updates with <commit>‘s <filename>.