Monday, March 9, 2015

GIT Commit-level Operation

The parameters that you pass to git reset and git checkoutdetermine their scope. When you don’t include a file path as a parameter, they operate on whole commits. That’s what we’ll be exploring in this section. Note that git revert has no file-level counterpart.

Reset

On the commit-level, resetting is a way to move the tip of a branch to a different commit. This can be used to remove commits from the current branch. For example, the following command moves the hotfix branch backwards by two commits.
git checkout hotfix
git reset HEAD~2
The two commits that were on the end of hotfix are now dangling commits, which means they will be deleted the next time Git performs a garbage collection. In other words, you’re saying that you want to throw away these commits. This can be visualized as the following:
This usage of git reset is a simple way to undo changes that haven’t been shared with anyone else. It’s your go-to command when you’ve started working on a feature and find yourself thinking, “Oh crap, what am I doing? I should just start over.”
In addition to moving the current branch, you can also get git resetto alter the staged snapshot and/or the working directory by passing it one of the following flags:
  • --soft – The staged snapshot and working directory are not altered in any way.
  • --mixed – The staged snapshot is updated to match the specified commit, but the working directory is not affected. This is the default option.
  • --hard – The staged snapshot and the working directory are both updated to match the specified commit.
It’s easier to think of these modes as defining the scope of a git reset operation:
These flags are often used with HEAD as the parameter. For instance,git reset --mixed HEAD has the affect of unstaging all changes, but leaves them in the working directory. On the other hand, if you want to completely throw away all your uncommitted changes, you would use git reset --hard HEAD. These are two of the most common uses of git reset.
Be careful when passing a commit other than HEAD to git reset, since this re-writes the current branch’s history. As discussed in The Golden Rule of Rebasing, this a big problem when working on a public branch.

Checkout

By now, you should be very familiar with the commit-level version of git checkout. When passed a branch name, it lets you switch between branches.
git checkout hotfix
Internally, all the above command does is move HEAD to a different branch and update the working directory to match. Since this has the potential to overwrite local changes, Git forces you to commit or stash any changes in the working directory that will be lost during the checkout operation. Unlike git resetgit checkout doesn’t move any branches around.
You can also check out arbitrary commits by passing in the commit reference instead of a branch. This does the exact same thing as checking out a branch: it moves the HEAD reference to the specified commit. For example, the following command will check out out the grandparent of the current commit:
git checkout HEAD~2
This is useful for quickly inspecting an old version of your project. However, since there is no branch reference to the current HEAD, this puts you in a detached HEAD state. This can be dangerous if you start adding new commits because there will be no way to get back to them after you switch to another branch. For this reason, you should always create a new branch before adding commits to a detached HEAD.

Revert

Reverting undoes a commit by creating a new commit. This is a safe way to undo changes, as it has no chance of re-writing the commit history. For example, the following command will figure out the changes contained in the 2nd to last commit, create a new commit undoing those changes, and tack the new commit onto the existing project.
git checkout hotfix
git revert HEAD~2
This can be visualized as the following:
Contrast this with git reset, which does alter the existing commit history. For this reason, git revert should be used to undo changes on a public branch, The parameters that you pass to git reset and git checkout determine their scope. When you don’t include a file path as a parameter, they operate on whole commits. That’s what we’ll be exploring in this section. Note that git revert has no file-level counterpart.

Reset
On the commit-level, resetting is a way to move the tip of a branch to a different commit. This can be used to remove commits from the current branch. For example, the following command moves the hotfix branch backwards by two commits.

git checkout hotfix
git reset HEAD~2
The two commits that were on the end of hotfix are now dangling commits, which means they will be deleted the next time Git performs a garbage collection. In other words, you’re saying that you want to throw away these commits. This can be visualized as the following:


This usage of git reset is a simple way to undo changes that haven’t been shared with anyone else. It’s your go-to command when you’ve started working on a feature and find yourself thinking, “Oh crap, what am I doing? I should just start over.”

In addition to moving the current branch, you can also get git reset to alter the staged snapshot and/or the working directory by passing it one of the following flags:

--soft – The staged snapshot and working directory are not altered in any way.
--mixed – The staged snapshot is updated to match the specified commit, but the working directory is not affected. This is the default option.
--hard – The staged snapshot and the working directory are both updated to match the specified commit.
It’s easier to think of these modes as defining the scope of a git reset operation:


These flags are often used with HEAD as the parameter. For instance, git reset --mixed HEAD has the affect of unstaging all changes, but leaves them in the working directory. On the other hand, if you want to completely throw away all your uncommitted changes, you would use git reset --hard HEAD. These are two of the most common uses of git reset.

Be careful when passing a commit other than HEAD to git reset, since this re-writes the current branch’s history. As discussed in The Golden Rule of Rebasing, this a big problem when working on a public branch.

Checkout
By now, you should be very familiar with the commit-level version of git checkout. When passed a branch name, it lets you switch between branches.

git checkout hotfix
Internally, all the above command does is move HEAD to a different branch and update the working directory to match. Since this has the potential to overwrite local changes, Git forces you to commit or stash any changes in the working directory that will be lost during the checkout operation. Unlike git reset, git checkout doesn’t move any branches around.


You can also check out arbitrary commits by passing in the commit reference instead of a branch. This does the exact same thing as checking out a branch: it moves the HEAD reference to the specified commit. For example, the following command will check out out the grandparent of the current commit:

git checkout HEAD~2

This is useful for quickly inspecting an old version of your project. However, since there is no branch reference to the current HEAD, this puts you in a detached HEAD state. This can be dangerous if you start adding new commits because there will be no way to get back to them after you switch to another branch. For this reason, you should always create a new branch before adding commits to a detached HEAD.

Revert
Reverting undoes a commit by creating a new commit. This is a safe way to undo changes, as it has no chance of re-writing the commit history. For example, the following command will figure out the changes contained in the 2nd to last commit, create a new commit undoing those changes, and tack the new commit onto the existing project.

git checkout hotfix
git revert HEAD~2
This can be visualized as the following:


Contrast this with git reset, which does alter the existing commit history. For this reason, git revert should be used to undo changes on a public branch, and git reset should be reserved for undoing changes on a private branch.

You can also think of git revert as a tool for undoing committed changes, while git reset HEAD is for undoing uncommitted changes.

Like git checkout, git revert has the potential to overwrite files in the working directory, so it will ask you to commit or stash changes that would be lost during the revert operation.and git reset should be reserved for undoing changes on a private branch.
You can also think of git revert as a tool for undoing committedchanges, while git reset HEAD is for undoing uncommitted changes.
Like git checkoutgit revert has the potential to overwrite files in the working directory, so it will ask you to commit or stash changes that would be lost during the revert operation.

No comments: