Adrian Andreias

Jul 17, 2014

More git trickery

Difference between working directory/stage/HEAD

git diff

Shows the changes between the working directory and the index. This shows what has been changed, but is not staged for a commit.

git diff --cached

Shows the changes between the index and the HEAD (which is the last commit on this branch). This shows what has been added to the index and staged for a commit.

git diff HEAD

Shows all the changes between the working directory and HEAD (which includes changes in the index). This shows all the changes since the last commit, whether or not they have been staged for commit or not.

Modify commit history: edit/split/merge commits

Do not modify commits that have already been pushed! Unimaginable nasty things can happen!

There is a guide to splitting commits in the rebase manual. The quick summary is:

  • Perform an interactive rebase including the target commit (e.g. git rebase -i "<commit-to-split>^" branch) and mark it to be edited. Note that double quotes are required in Windows, otherwise the caret symbol will be interpreted by cmd.exe by escaping the following character. You can also specify the commit before the one you want to edit, this time without the caret: git rebase -i <the-commit-before> branch
  • When the rebase reaches that commit, use git reset "HEAD^" to reset to before the commit, but keep your work tree intact.
  • Incrementally add changes and commit them, making as many commits as desired. add -p can be useful to add only some of the changes in a given file. Use commit -c ORIG_HEAD if you want to re-use the original commit message for a certain commit.
  • You can also git commit --amend in order to modify a commit, otherwise new commits will be created.
  • If you want to test what you're committing (good idea!) use git stash to hide away the part you haven't committed (or stash --keep-index before you even commit it), test, then git stash pop to return the rest to the work tree. Keep making commits until you get all modifications committed, i.e. have a clean work tree.
  • You can also abort your rebase if you messed things up completely: git rebase --abort
  • Run git rebase --continue to proceed applying the commits after the now-split commit.

Based on:

Restoring lost commits

Assuming you ran git reset --hard HEAD^ or just messed with rebasing causing you to lose a commit or more. Don't panic. Git should still have your commits in the data store until the next garbage collection cleans it up, unless you ran git gc.

So your commit(s) doesn't show up when you run git log, you should see them when running git flog. Identify in the flog the commit you want to switch to and run:

git merge <commit-hash>

Show file at specified revision

git show 2c624a9:a.txt git show HEAD~3:a.txt git show "HEAD^":a.txt