git show <hash>:<file>
git log -p <filename>
git log -S<string>
git log --all -- **/thefile.*
git checkout <deletion-SHA>^ -- <path-to-file>
Two ways to do this (from this StackOverflow answer):
git add $(git ls-files -o --exclude-standard)
- set an alias for this if you care togit add -i
a
*
q
Useful options:
--cached - diffs against files that are currently staged (ready to commit)
Useful tips:
- You can pipe the result of your diffs to a visual diff tool like p4merge or just to an editor like Sublime Text. I frequently run
git diff [options] | subl
to manage various diffs when comparing history.
git diff <earlier commit hash>..<later commit hash>
git diff [<earlier hash>[..<later hash>]] -- '*.ext'
git diff --stat
This one's a little janky. Not useful if you already have stuff staged.
git add -A
git diff --cached
- (optional)
git diff reset HEAD
if you want to unstage
git add -N .
git diff --cached
- (optional)
git diff reset HEAD
if you want to unstage
git diff --no-index <file1> <file2>
This totally annihilates everything.
git reset --hard HEAD
to delete all unstaged changesgit clean -fd
to delete all untracked files
All of these patterns will rewrite your history. If you force push them to a branch or repo with other contributors, they will be very unhappy with you. Make sure you know what you're doing.
You might do this to clean up your work before merging to master.
-
git rebase -i HEAD~<number of commits>
-
Change every commit below the top one to have
f
(fixup
) instead ofpick
, which will combine them with the top onepick 849c994 Do the thing f b02404e Oops, a typo f 107184a I know how to spell
-
If necessary, reword your resulting single commit with
git commit --amend
or replace the top commit'spick
withr
(reword
) to amend it during the rebase step.
git reset HEAD~1
to go back one commit and have all files unstaged- Make edits
- Stage your files:
- I want to keep most of my changes:
git add -A
,git reset HEAD <individual files>
- I want to keep only some of my changes:
git add <individual files>
git commit
your staged changesgit stash
leftover changes if you want to keep them around, orgit reset --hard HEAD
to get rid of them
You might do this in order to better compartmentalize your work, split one task into two, or make it easier to code review. This is extremely similar to the above step.
- Rebase one past your target commit (pick one of these):
git rebase -i HEAD~<how many commits back target commit is, +1>
(so if your commit is 2 back, you would wantHEAD~3
)git rebase -i <hash of commit before target commit>
git reset HEAD~1
to remove your commit but keep the changes in working indexgit add
your files for your first commitgit commit
your files for your first commit- Repeat steps 3 and 4 until satisfied
git rebase --continue
to finish
We can move work from a newer commit to an older one with git rebase
. Since it's not actually possible to see the changes of the newer commit when you're editing the older one, it's recommended that you output the diff of changes made in the new commit so you can reference what files were changed.
git rebase -i <hash of commit before older commit>
- Take note of the hash of the commit you want to get changes from
- Change the older commit you want to move work into from
pick
toe
(edit
) - Get the changes from the newer commit, multiple ways to do this:
git checkout <hash of newer commit you want changes from> -- <file>
- Copy the changes from your diff manually
git commit --amend
git rebase --continue
git rebase -i <hash of commit before older commit>
- Change both the older commit and new commit from
pick
toe
(edit
) - Copy the old commit's message (if you want to keep it the same)
git reset HEAD~1
- Stage the changes you want to keep
git commit -m "<your (copied) message>"
git rebase --continue
- you'll now be at the edit step of the newer commitgit add -A
- add the changes that are leftovergit commit --amend
git rebase --continue
This is good for if you accidentally merge a credentials file. Sourced from StackOverflow: http://stackoverflow.com/questions/307828/completely-remove-file-from-all-git-repository-commit-history
# create and check out a temporary branch at the location of the bad merge
git checkout -b tmpfix <sha1-of-merge>
# remove the incorrectly added file
git rm somefile.orig
# commit the amended merge
git commit --amend
# go back to the master branch
git checkout master
# replant the master branch onto the corrected merge
git rebase tmpfix
# delete the temporary branch
git branch -d tmpfix
Note: this is probably an easier way to do this.
Maybe you have a ticket you did most of the work on and you need to squash, but someone else started the work with a commit.
-
git rebase -i <hash of commit before target commit>
-
Like squashing, change every commit you want to squash from
pick
tof
. Change your target commit frompick
toe
to edit it:e 9beea7f The commit you want to claim pick 849c994 Some changes pick b02404e More changes pick 107184a The above two commits messages are terrible commit messages, fyi
-
git reset HEAD~1
- pop off the commit -
git add -A
- stage the changes -
git commit -m "All your commits are belong to us"
- commit it again -
git rebase --continue
- all the changes should be squashed, with you credit as the owner.
If someone has pushed force work to a branch feature-a
, but you began work locally from a point in the past, you may still be at a point where your changes can successfully apply to that branch.
When you branched, the history looked like:
abc Commit 1
def Commit 2
ghi Commit 3 <- you started here
Your local work looks like:
abc Commit 1
def Commit 2
ghi Commit 3
jkl Commit 4 <- you are here
Now the remote looks like:
abc Commit 1
def Commit 2
mno Commit 3-oops <- updated
To catch your new commit jkl
up to the origin:
-
git fetch origin
-
git rebase -i origin/<branch name>
: - delete the no-longer relevantghi Commit 3
# pick ghi Commit 3 pick jkl Commit 4
-
Resolve merge conflicts (if any arise).
-
git rebase --continue
-
Result:
abc Commit 1 def Commit 2 mno Commit 3-oops jkl Commit 4
Weird stuff you can do and might want to do for some weird reason.
Maybe you want to stash a changeset, and pop it out to play with it, without losing the set of stashed changes you know are good. You can preserve what's in your stash by forcing a merge conflict.
git stash save
your changes- Edit one of the files you changed in your stash in such a way that it will cause a merge conflict - you can just throw some nonsense into a line you know you changed.
git commit [--allow-empty-message -m ""]
- commit it so that stash will allow you to pop (make it empty if you want since it's a trash commit)git stash pop [stash@{#}]
- Your stashed changes will conflict with your trash commit, keeping the original set of changes in your stash while putting a (conflicted) copy into your working index. Simply resolve the conflict you created and continue on your experiments.