diff --git a/README.md b/README.md index 9fca9e8..253d364 100644 --- a/README.md +++ b/README.md @@ -19,55 +19,73 @@ For clarity's sake all examples in this document use a customized bash prompt in **Table of Contents** *generated with [DocToc](https://github.com/thlorenz/doctoc)* - - [I wrote the wrong thing in a commit message](#i-wrote-the-wrong-thing-in-a-commit-message) - - [I need to add staged changes to the previous commit](#i-need-to-add-staged-changes-to-the-previous-commit) + - [Editing Commits](#editing-commits) + - [What did I just commit?](#what-did-i-just-commit) + - [I wrote the wrong thing in a commit message](#i-wrote-the-wrong-thing-in-a-commit-message) + - [I committed with the wrong name and email configured](#i-committed-with-the-wrong-name-and-email-configured) + - [I want to remove a file from a commit](#i-want-to-remove-a-file-from-a-commit) + - [I want to delete or remove my last commit](#i-want-to-delete-or-remove-my-last-commit) + - [Delete/remove arbitrary commit](#deleteremove-arbitrary-commit) - [I tried to push my amended commit to a remote, but I got an error message](#i-tried-to-push-my-amended-commit-to-a-remote-but-i-got-an-error-message) + - [I accidentally did a hard reset, and I want my changes back](#i-accidentally-did-a-hard-reset-and-i-want-my-changes-back) + - [Staging](#staging) + - [I need to add staged changes to the previous commit](#i-need-to-add-staged-changes-to-the-previous-commit) + - [I want to stage part of a new file, but not the whole file](#i-want-to-stage-part-of-a-new-file-but-not-the-whole-file) + - [I want to add changes in one file to two different commits](#i-want-to-add-changes-in-one-file-to-two-different-commits) + - [Unstaged Edits](#unstaged-edits) + - [I want to move my unstaged edits to a new branch](#i-want-to-move-my-unstaged-edits-to-a-new-branch) + - [I want to move my unstaged edits to a different, existing branch](#i-want-to-move-my-unstaged-edits-to-a-different-existing-branch) + - [I want to discard my local, uncommitted changes](#i-want-to-discard-my-local-uncommitted-changes) + - [Branches](#branches) + - [I pulled from/into the wrong branch](#i-pulled-frominto-the-wrong-branch) + - [I want to discard local commits so my branch is the same as one on the server](#i-want-to-discard-local-commits-so-my-branch-is-the-same-as-one-on-the-server) + - [I committed to master instead of a new branch](#i-committed-to-master-instead-of-a-new-branch) + - [I made several commits on a single branch that should be on different branches](#i-made-several-commits-on-a-single-branch-that-should-be-on-different-branches) + - [I want to delete local branches that were deleted upstream](#i-want-to-delete-local-branches-that-were-deleted-upstream) + - [I accidentally deleted my branch](#i-accidentally-deleted-my-branch) + - [I want to delete a branch](#i-want-to-delete-a-branch) + - [Rebasing and Merging](#rebasing-and-merging) - [I rebased, but I don't want to force push.](#i-rebased-but-i-dont-want-to-force-push) - - [I need to combine commits](#i-need-to-combine-commits) - - [Possible issues with merging](#possible-issues-with-merging) - - [Safe merging strategy:](#safe-merging-strategy) + - [I need to combine commits](#i-need-to-combine-commits) + - [Safe merging strategy](#safe-merging-strategy) - [I need to merge a branch into a single commit](#i-need-to-merge-a-branch-into-a-single-commit) - [I want to combine only unpushed commits](#i-want-to-combine-only-unpushed-commits) + - [Check if all commits on a branch are merged](#check-if-all-commits-on-a-branch-are-merged) - [Possible issues with interactive rebases](#possible-issues-with-interactive-rebases) - [The rebase editing screen says 'noop'](#the-rebase-editing-screen-says-noop) - [There were conflicts](#there-were-conflicts) - - [I committed with the wrong name and email configured](#i-committed-with-the-wrong-name-and-email-configured) - - [I committed to master instead of a new branch](#i-committed-to-master-instead-of-a-new-branch) - - [I made several commits on a single branch that should be on different branches](#i-made-several-commits-on-a-single-branch-that-should-be-on-different-branches) - - [I want to add part of a new file, but not the whole file](#i-want-to-add-part-of-a-new-file-but-not-the-whole-file) - - [I want to add aliases for some git commands](#i-want-to-add-aliases-for-some-git-commands) - - [I pulled from/into the wrong branch](#i-pulled-frominto-the-wrong-branch) - - [I want to discard local commits so my branch is the same as one on the server](#i-want-to-discard-local-commits-so-my-branch-is-the-same-as-one-on-the-server) - - [I want to discard my local, uncommitted changes](#i-want-to-discard-my-local-uncommitted-changes) - - [I accidentally did a hard reset, and I want my changes back](#i-accidentally-did-a-hard-reset-and-i-want-my-changes-back) - - [I want to move my unstaged edits to a new branch](#i-want-to-move-my-unstaged-edits-to-a-new-branch) - - [I want to move my unstaged edits to a different, existing branch](#i-want-to-move-my-unstaged-edits-to-a-different-existing-branch) - - [What did I just do?](#what-did-i-just-do) - - [I want to add changes in one file to two different commits](#i-want-to-add-changes-in-one-file-to-two-different-commits) - - [I want to remove a file from git but keep the file](#i-want-to-remove-a-file-from-git-but-keep-the-file) - - [I want to remove a file from a commit](#i-want-to-remove-a-file-from-a-commit) - - [I want to change a file name's capitalization, without changing the contents of the file.](#i-want-to-change-a-file-names-capitalization-without-changing-the-contents-of-the-file) - - [Clone all submodules](#clone-all-submodules) - - [Deleting Objects](#deleting-objects) - - [I want to delete local branches that were deleted upstream](#i-want-to-delete-local-branches-that-were-deleted-upstream) - - [I accidentally deleted my branch](#i-accidentally-deleted-my-branch) - - [I want to delete or remove my last commit](#i-want-to-delete-or-remove-my-last-commit) - - [Delete/remove arbitrary commit](#deleteremove-arbitrary-commit) - - [I want to delete a branch](#i-want-to-delete-a-branch) + - [Miscellaneous Objects](#miscellaneous-objects) + - [Clone all submodules](#clone-all-submodules) - [Delete tag](#delete-tag) - - [Deleted Patch](#deleted-patch) - - [Check if all commits on a branch are merged](#check-if-all-commits-on-a-branch-are-merged) + - [Deleted Patch](#deleted-patch) + - [Tracking Files](#tracking-files) + - [I want to change a file name's capitalization, without changing the contents of the file.](#i-want-to-change-a-file-names-capitalization-without-changing-the-contents-of-the-file) + - [I want to remove a file from git but keep the file](#i-want-to-remove-a-file-from-git-but-keep-the-file) + - [Configuration](#configuration) + - [I want to add aliases for some git commands](#i-want-to-add-aliases-for-some-git-commands) - [I've no idea what I did wrong](#ive-no-idea-what-i-did-wrong) - [Other Resources](#other-resources) - [Books](#books) - [Tutorials](#tutorials) - - [Scripts & Tools](#scripts-&-tools) + - [Scripts and Tools](#scripts-and-tools) - [GUI Clients](#gui-clients) - -## I wrote the wrong thing in a commit message + +## Editing Commits + + +### What did I just commit? + +Let's say that you just blindly committed changes with `git commit -a` and you're not sure what the actual content of the commit you just made was. You can check the difference between your current HEAD and what your HEAD just was with: + +```sh +(master)$ git diff HEAD@{1} HEAD +``` + + +### I wrote the wrong thing in a commit message If you wrote the wrong thing and the commit has not yet been pushed, you can do the following to change the commit message: @@ -84,14 +102,61 @@ $ git commit -a -m 'xxxxxxx' If you have already pushed the message, you can amend the commit and force push, but this is not recommended. -## I need to add staged changes to the previous commit + +### I committed with the wrong name and email configured + +If it's a single commit, amend it ```sh -(my-branch*)$ git commit --amend +$ git commit --amend --author "New Authorname " +``` + +If you need to change all of history, see the man page for 'git filter-branch'. + + + +### I want to remove a file from a commit + +In order to remove a file from a commit, do the following: + +```sh +$ git checkout HEAD~2 myfile +$ git add -A +$ git commit --amend +``` + +This is particularly useful when you have an open patch and you have commited an unnecessary file, and need to force push to update the patch on a remote. + + +### I want to delete or remove my last commit + +If you need to delete pushed commits, you can use the following. However, it will irreversabily change your history, and mess up the history of anyone else who had already pulled from the repository. In short, if you're not sure, you should never do this, ever. + +```sh +$ git reset HEAD^ --hard +$ git push -f [remote] [branch] +``` + +If you haven't pushed, to reset Git to the state it was in before you made your last commit (while keeping your staged changes): + +``` +(my-branch*)$ git reset --soft HEAD@{1} ``` - +This only works if you haven't pushed. If you have pushed, the only truly safe thing to do is `git revert SHAofBadCommit`. That will create a new commit that undoes all the previous commit's changes. Or, if the branched you pushed to is rebase-safe (ie. other devs aren't expected to pull from it), you can just use `git push -f`. For more, see [the above section](#deleteremove-last-pushed-commit). + + +### Delete/remove arbitrary commit + +The same warning applies as above. Never do this if possible. + +```sh +$ git rebase --onto SHA1_OF_BAD_COMMIT^ SHA1_OF_BAD_COMMIT +$ git push -f [remote] [branch] +``` + + ### I tried to push my amended commit to a remote, but I got an error message ```sh @@ -112,6 +177,343 @@ Note that, as with rebasing (see below), amending **replaces the old commit with In general, **avoid force pushing**. It is best to create and push a new commit rather than force-pushing the amended commit as it has will cause conflicts in the source history for any other developer who has interacted with the branch in question or any child branches. + + +### I accidentally did a hard reset, and I want my changes back + +If you accidentally do `git reset --hard`, you can normally still get your commit back, as git keeps a log of everything for a few days. + +```sh +(master)$ git reflog +``` + +You'll see a list of your past commits, and a commit for the reset. Choose the SHA of the commit you want to return to, and reset again: + +```sh +(master)$ git reset --hard SHA1234 +``` + +And you should be good to go. + +## Staging + + +### I need to add staged changes to the previous commit + +```sh +(my-branch*)$ git commit --amend + +``` + + +### I want to stage part of a new file, but not the whole file + +Normally, if you want to stage part of a file, you run this: + +```sh +$ git add --patch filename.x +``` + +`-p` will work for short. This will open interactive mode. You would be able to use the `s` option to split the commit - however, if the file is new, you will not have this option. To add a new file, do this: + +```sh +$ git add -N filename.x +``` + +Then, you will need to use the `e` option to manually choose which lines to add. Running `git diff --cached` will show you which lines you have staged compared to which are still saved locally. + + + +### I want to add changes in one file to two different commits + +`git add` will add the entire file to a commit. `git add -p` will allow to interactively select which changes you want to add. + + +## Unstaged Edits + + +### I want to move my unstaged edits to a new branch + +```sh +$ git checkout -b my-branch +``` + + +### I want to move my unstaged edits to a different, existing branch + +```sh +$ git stash +$ git checkout my-branch +$ git stash pop +``` + + +### I want to discard my local, uncommitted changes + +If you want to only reset to some commit between origin and your local, you can do this: + +```sh +# one commit +(my-branch)$ git reset --hard HEAD^ +# two commits +(my-branch)$ git reset --hard HEAD^^ +# four commits +(my-branch)$ git reset --hard HEAD~4 +# or +(master)$ git checkout -f +``` + +To reset only a specific file, you can use that the filename as the argument: + +```sh +$ git reset filename +``` + +## Branches + + +### I pulled from/into the wrong branch + +This is another chance to use `git reflog` to see where your HEAD pointed before the bad pull. + +```sh +(master)$ git reflog +ab7555f HEAD@{0}: pull origin wrong-branch: Fast-forward +c5bc55a HEAD@{1}: checkout: checkout message goes here +``` + +Simply reset your branch back to the desired commit: + +```sh +$ git reset --hard c5bc55a +``` + +Done. + + +### I want to discard local commits so my branch is the same as one on the server + +Confirm that you haven't pushed your changes to the server. + +`git status` should show how many commits you are ahead of origin: + +```sh +(my-branch)$ git status +# On branch my-branch +# Your branch is ahead of 'origin/my-branch' by 2 commits. +# (use "git push" to publish your local commits) +# +``` + +One way of reseting to match origin (to have the same as what is on the remote) is to do this: + +```sh +(master)$ git reset --hard origin/my-branch +``` + + +### I committed to master instead of a new branch + +Create the new branch while remaining on master: + +```sh +(master)$ git checkout -b my-branch +(my-branch)$ git checkout master +(master)$ +``` + +Reset the branch master to the previous commit: + +```sh +(master)$ git reset --hard HEAD^ +``` + +`HEAD^` is short for `HEAD^1`. You can reset further through the generations by specifying which `HEAD` to set to. + +Alternatively, if you don't want to use `HEAD^`, find out what the commit hash you want to set your master branch to (`git log` should do the trick). Then reset to that hash. `git push` will make sure that this change is reflected on your remote. + +For example, if the hash of the commit that your master branch is supposed to be at is `a13b85e`: + +```sh +(master)$ git reset --hard a13b85e +HEAD is now at a13b85e +``` + +Checkout the new branch to continue working: + +```sh +(master)$ git checkout my-branch +``` + + +### I made several commits on a single branch that should be on different branches + +Say you are on your master branch. Running `git log`, you see you have made two commits: + +```sh +(master)$ git log + +commit e3851e817c451cc36f2e6f3049db528415e3c114 +Author: Alex Lee +Date: Tue Jul 22 15:39:27 2014 -0400 + + Bug #21 - Added CSRF protection + +commit 5ea51731d150f7ddc4a365437931cd8be3bf3131 +Author: Alex Lee +Date: Tue Jul 22 15:39:12 2014 -0400 + + Bug #14 - Fixed spacing on title + +commit a13b85e984171c6e2a1729bb061994525f626d14 +Author: Aki Rose +Date: Tue Jul 21 01:12:48 2014 -0400 + + First commit +``` + +Let's take note of our commit hashes for each bug (`e3851e8` for #21, `5ea5173` for #14). + +First, let's reset our master branch to the correct commit (`a13b85e`): + +```sh +(master)$ git reset --hard a13b85e +HEAD is now at a13b85e +``` + +Now, we can create a fresh branch for our bug #21 branch: + +```sh +(master)$ git checkout -b 21 +(21)$ +``` + +Now, let's *cherry-pick* the commit for bug #21 on top of our branch. That means we will be applying that commit, and only that commit, directly on top of whatever our head is at. + +```sh +(21)$ git cherry-pick e3851e8 +``` + +At this point, there is a possibility there might be conflicts. See the [**There were conflicts**](#merge-conflict) section in the [interactive rebasing section above](#interactive-rebase) for how to resolve conflicts. + + +Now let's create a new branch for bug #14, also based on master + +```sh +(21)$ git checkout master +(master)$ git checkout -b 14 +(14)$ +``` + +And finally, let's cherry-pick the commit for bug #14: + +```sh +(14)$ git cherry-pick 5ea5173 +``` + + + +### I want to delete local branches that were deleted upstream +Once you merge a pull request on github, it gives you the option to delete the merged branch in your fork. If you aren't planning to keep working on the branch, it's cleaner to delete the local copies of the branch so you don't end up cluttering up your working checkout with a lot of stale branches. + +```sh +$ git fetch -p +``` + + +### I accidentally deleted my branch + +If you're regularly pushing to remote, you should be safe most of the time. But still sometimes you may end up deleting your branches. Let's say we create a branch and create a new file: + +```sh +(master)$ git checkout -b my-branch +(my-branch)$ git branch +(my-branch)$ touch foo.txt +(my-branch)$ ls +README.md foo.txt +``` + +Let's add it and commit. + +```sh +(my-branch)$ git add . +(my-branch)$ git commit -m 'foo.txt added' +(my-branch)$ foo.txt added + 1 files changed, 1 insertions(+) + create mode 100644 foo.txt +(my-branch)$ git log + +commit 4e3cd85a670ced7cc17a2b5d8d3d809ac88d5012 +Author: siemiatj +Date: Wed Jul 30 00:34:10 2014 +0200 + + foo.txt added + +commit 69204cdf0acbab201619d95ad8295928e7f411d5 +Author: Kate Hudson +Date: Tue Jul 29 13:14:46 2014 -0400 + + Fixes #6: Force pushing after amending commits +``` + +Now we're switching back to master and 'accidentaly' removing our branch. + +```sh +(my-branch)$ git checkout master +Switched to branch 'master' +Your branch is up-to-date with 'origin/master'. +(master)$ git branch -D my-branch +Deleted branch my-branch (was 4e3cd85). +(master)$ echo oh noes, deleted my branch! +oh noes, deleted my branch! +``` + +At this point you should get familiar with 'reflog', an upgraded logger. It stores the history of all the action in the repo. + +``` +(master)$ git reflog +69204cd HEAD@{0}: checkout: moving from my-branch to master +4e3cd85 HEAD@{1}: commit: foo.txt added +69204cd HEAD@{2}: checkout: moving from master to my-branch +``` + +As you can see we have commit hash from our deleted branch. Let's see if we can restore our deleted branch. + +```sh +(master)$ git checkout -b my-branch-help +Switched to a new branch 'my-branch-help' +(my-branch-help)$ git reset --hard 4e3cd85 +HEAD is now at 4e3cd85 foo.txt added +(my-branch-help)$ ls +README.md foo.txt +``` + +Voila! We got our removed file back. Git reflog is also useful when rebasing goes terribly wrong. + + +### I want to delete a branch + +To delete a remote branch: + +```sh +(master)$ git push origin --delete my-branch +``` + +You can also do: + +```sh +(master)$ git push origin :my-branch +``` + +To delete a local branch: + +```sh +(master)$ git branch -D my-branch +``` + + +## Rebasing and Merging + ### I rebased, but I don't want to force push. @@ -127,7 +529,7 @@ Unfortunately, you have to force push, if you want those changes to be reflected For more, see [this SO thread](http://stackoverflow.com/questions/11058312/how-can-i-use-git-rebase-without-requiring-a-forced-push). -## I need to combine commits +### I need to combine commits You need to do something called an interactive rebase. @@ -209,8 +611,7 @@ If everything is successful, you should see something like this: (master)$ Successfully rebased and updated refs/heads/master. ``` -### Possible issues with merging -#### Safe merging strategy: +#### Safe merging strategy `--no-commit` performs the merge but pretends the merge failed and does not autocommit, giving the user a chance to inspect and further tweak the merge result before committing. `no-ff` maintains evidence that a feature branch once existed, keeping project history consistent. ```sh @@ -234,6 +635,20 @@ Sometimes you have several work in progress commits that you want to combine bef This will do an interactive rebase that lists only the commits that you haven't already pushed, so it will be safe to reorder/fix/squash anything in the list. + +### Check if all commits on a branch are merged + +To check if all commits on a branch are merged into another branch, you should diff between the heads (or any commits) of those branches: + +```sh +(master)$ git log --graph --left-right --cherry-pick --oneline HEAD...feature/120-on-scroll +``` + +This will tell you if any commits are in one but not the other, and will give you a list of any nonshared between the branches. Another option is to do this: + +```sh +(master)$ git log master ^feature/120-on-scroll --no-merges +``` ### Possible issues with interactive rebases @@ -298,136 +713,57 @@ If at any time you want to stop the entire rebase and go back to the original st (my-branch)$ git rebase --abort ``` - -## I committed with the wrong name and email configured + +## Miscellaneous Objects -If it's a single commit, amend it + +### Clone all submodules ```sh -$ git commit --amend --author "New Authorname " +$ git clone --recursive git://github.com/foo/bar.git ``` -If you need to change all of history, see the man page for 'git filter-branch' - - -## I committed to master instead of a new branch - -Create the new branch while remaining on master: +If already cloned: ```sh -(master)$ git checkout -b my-branch -(my-branch)$ git checkout master -(master)$ +$ git submodule update --init --recursive ``` -Reset the branch master to the previous commit: + +### Delete tag ```sh -(master)$ git reset --hard HEAD^ +$ git tag -d +$ git push :refs/tags/ ``` -`HEAD^` is short for `HEAD^1`. You can reset further through the generations by specifying which `HEAD` to set to. + +### Deleted Patch -Alternatively, if you don't want to use `HEAD^`, find out what the commit hash you want to set your master branch to (`git log` should do the trick). Then reset to that hash. `git push` will make sure that this change is reflected on your remote. +If someone has sent you a pull request on GitHub, but then deleted their original fork, you will be unable to clone their commits or to use `git am`. In such cases, it is best to manually look at their commits and copy them into a new branch on your local. Then, commit. -For example, if the hash of the commit that your master branch is supposed to be at is `a13b85e`: +After commiting, change the author of the previous commit. To do this, see how to [change author](#commit-wrong-author). Then, apply whatever changes needed on to, and make a new pull request. + +## Tracking Files + + +### I want to change a file name's capitalization, without changing the contents of the file. ```sh -(master)$ git reset --hard a13b85e -HEAD is now at a13b85e +(master)$ git mv --force myfile MyFile ``` -Checkout the new branch to continue working: + +### I want to remove a file from git but keep the file ```sh -(master)$ git checkout my-branch +(master)$ git rm --cached log.txt ``` - -## I made several commits on a single branch that should be on different branches - -Say you are on your master branch. Running `git log`, you see you have made two commits: - -```sh -(master)$ git log - -commit e3851e817c451cc36f2e6f3049db528415e3c114 -Author: Alex Lee -Date: Tue Jul 22 15:39:27 2014 -0400 - - Bug #21 - Added CSRF protection - -commit 5ea51731d150f7ddc4a365437931cd8be3bf3131 -Author: Alex Lee -Date: Tue Jul 22 15:39:12 2014 -0400 - - Bug #14 - Fixed spacing on title - -commit a13b85e984171c6e2a1729bb061994525f626d14 -Author: Aki Rose -Date: Tue Jul 21 01:12:48 2014 -0400 - - First commit -``` - -Let's take note of our commit hashes for each bug (`e3851e8` for #21, `5ea5173` for #14). - -First, let's reset our master branch to the correct commit (`a13b85e`): - -```sh -(master)$ git reset --hard a13b85e -HEAD is now at a13b85e -``` - -Now, we can create a fresh branch for our bug #21 branch: - -```sh -(master)$ git checkout -b 21 -(21)$ -``` - -Now, let's *cherry-pick* the commit for bug #21 on top of our branch. That means we will be applying that commit, and only that commit, directly on top of whatever our head is at. - -```sh -(21)$ git cherry-pick e3851e8 -``` - -At this point, there is a possibility there might be conflicts. See the [**There were conflicts**](#merge-conflict) section in the [interactive rebasing section above](#interactive-rebase) for how to resolve conflicts. - - -Now let's create a new branch for bug #14, also based on master - -```sh -(21)$ git checkout master -(master)$ git checkout -b 14 -(14)$ -``` - -And finally, let's cherry-pick the commit for bug #14: - -```sh -(14)$ git cherry-pick 5ea5173 -``` - - -## I want to add part of a new file, but not the whole file - -Normally, if you want to stage part of a file, you run this: - -```sh -$ git add --patch filename.x -``` - -`-p` will work for short. This will open interactive mode. You would be able to use the `s` option to split the commit - however, if the file is new, you will not have this option. To add a new file, do this: - -```sh -$ git add -N filename.x -``` - -Then, you will need to use the `e` option to manually choose which lines to add. Running `git diff --cached` will show you which lines you have staged compared to which are still saved locally. +## Configuration -## I want to add aliases for some git commands +### I want to add aliases for some git commands On OS X and Linux, your git configuration file is stored in ```~/.gitconfig```. I've added some example aliases I use as shortcuts (and some of my common typos) in the ```[aliases]``` section as shown below: @@ -454,311 +790,6 @@ On OS X and Linux, your git configuration file is stored in ```~/.gitconfig```. zap = fetch -p ``` - -## I pulled from/into the wrong branch - -This is another chance to use `git reflog` to see where your HEAD pointed before the bad pull. - -```sh -(master)$ git reflog -ab7555f HEAD@{0}: pull origin wrong-branch: Fast-forward -c5bc55a HEAD@{1}: checkout: checkout message goes here -``` - -Simply reset your branch back to the desired commit: - -```sh -$ git reset --hard c5bc55a -``` - -Done. - - -## I want to discard local commits so my branch is the same as one on the server - -Confirm that you haven't pushed your changes to the server. - -`git status` should show how many commits you are ahead of origin: - -```sh -(my-branch)$ git status -# On branch my-branch -# Your branch is ahead of 'origin/my-branch' by 2 commits. -# (use "git push" to publish your local commits) -# -``` - -One way of reseting to match origin (to have the same as what is on the remote) is to do this: - -```sh -(master)$ git reset --hard origin/my-branch -``` - - -## I want to discard my local, uncommitted changes - -If you want to only reset to some commit between origin and your local, you can do this: - -```sh -# one commit -(my-branch)$ git reset --hard HEAD^ -# two commits -(my-branch)$ git reset --hard HEAD^^ -# four commits -(my-branch)$ git reset --hard HEAD~4 -# or -(master)$ git checkout -f -``` - -To reset only a specific file, you can use that the filename as the argument: - -```sh -$ git reset filename -``` - - -## I accidentally did a hard reset, and I want my changes back - -If you accidentally do `git reset --hard`, you can normally still get your commit back, as git keeps a log of everything for a few days. - -```sh -(master)$ git reflog -``` - -You'll see a list of your past commits, and a commit for the reset. Choose the SHA of the commit you want to return to, and reset again: - -```sh -(master)$ git reset --hard SHA1234 -``` - -And you should be good to go. - - -## I want to move my unstaged edits to a new branch - -```sh -$ git checkout -b my-branch -``` - - -## I want to move my unstaged edits to a different, existing branch - -```sh -$ git stash -$ git checkout my-branch -$ git stash pop -``` - - -## What did I just do? - -Let's say that you just blindly committed changes with `git commit -a` and you're not sure what the actual content of the commit you just made was. You can check the difference between your current HEAD and what your HEAD just was with: - -```sh -(master)$ git diff HEAD@{1} HEAD -``` - - -## I want to add changes in one file to two different commits - -`git add` will add the entire file to a commit. `git add -p` will allow to interactively select which changes you want to add. - - -## I want to remove a file from git but keep the file - -```sh -(master)$ git rm --cached log.txt -``` - - -## I want to remove a file from a commit - -In order to remove a file from a commit, do the following: - -```sh -$ git checkout HEAD~2 myfile -$ git add -A -$ git commit --amend -``` - -This is particularly useful when you have an open patch and you have commited an unnecessary file, and need to force push to update the patch on a remote. - - -## I want to change a file name's capitalization, without changing the contents of the file. - -```sh -(master)$ git mv --force myfile MyFile -``` - - -## Clone all submodules - -```sh -$ git clone --recursive git://github.com/foo/bar.git -# If already cloned: -$ git submodule update --init --recursive -``` - - -## Deleting Objects - - -### I want to delete local branches that were deleted upstream -Once you merge a pull request on github, it gives you the option to delete the merged branch in your fork. If you aren't planning to keep working on the branch, it's cleaner to delete the local copies of the branch so you don't end up cluttering up your working checkout with a lot of stale branches. - -```sh -$ git fetch -p -``` - - -### I accidentally deleted my branch - -If you're regularly pushing to remote, you should be safe most of the time. But still sometimes you may end up deleting your branches. Let's say we create a branch and create a new file: - -```sh -(master)$ git checkout -b my-branch -(my-branch)$ git branch -(my-branch)$ touch foo.txt -(my-branch)$ ls -README.md foo.txt -``` - -Let's add it and commit. - -```sh -(my-branch)$ git add . -(my-branch)$ git commit -m 'foo.txt added' -(my-branch)$ foo.txt added - 1 files changed, 1 insertions(+) - create mode 100644 foo.txt -(my-branch)$ git log - -commit 4e3cd85a670ced7cc17a2b5d8d3d809ac88d5012 -Author: siemiatj -Date: Wed Jul 30 00:34:10 2014 +0200 - - foo.txt added - -commit 69204cdf0acbab201619d95ad8295928e7f411d5 -Author: Kate Hudson -Date: Tue Jul 29 13:14:46 2014 -0400 - - Fixes #6: Force pushing after amending commits -``` - -Now we're switching back to master and 'accidentaly' removing our branch. - -```sh -(my-branch)$ git checkout master -Switched to branch 'master' -Your branch is up-to-date with 'origin/master'. -(master)$ git branch -D my-branch -Deleted branch my-branch (was 4e3cd85). -(master)$ echo oh noes, deleted my branch! -oh noes, deleted my branch! -``` - -At this point you should get familiar with 'reflog', an upgraded logger. It stores the history of all the action in the repo. - -``` -(master)$ git reflog -69204cd HEAD@{0}: checkout: moving from my-branch to master -4e3cd85 HEAD@{1}: commit: foo.txt added -69204cd HEAD@{2}: checkout: moving from master to my-branch -``` - -As you can see we have commit hash from our deleted branch. Let's see if we can restore our deleted branch. - -```sh -(master)$ git checkout -b my-branch-help -Switched to a new branch 'my-branch-help' -(my-branch-help)$ git reset --hard 4e3cd85 -HEAD is now at 4e3cd85 foo.txt added -(my-branch-help)$ ls -README.md foo.txt -``` - -Voila! We got our removed file back. Git reflog is also useful when rebasing goes terribly wrong. - - -### I want to delete or remove my last commit - -If you need to delete pushed commits, you can use the following. However, it will irreversabily change your history, and mess up the history of anyone else who had already pulled from the repository. In short, if you're not sure, you should never do this, ever. - -```sh -$ git reset HEAD^ --hard -$ git push -f [remote] [branch] -``` - -If you haven't pushed, to reset Git to the state it was in before you made your last commit (while keeping your staged changes): - -``` -(my-branch*)$ git reset --soft HEAD@{1} - -``` - -This only works if you haven't pushed. If you have pushed, the only truly safe thing to do is `git revert SHAofBadCommit`. That will create a new commit that undoes all the previous commit's changes. Or, if the branched you pushed to is rebase-safe (ie. other devs aren't expected to pull from it), you can just use `git push -f`. For more, see [the above section](#deleteremove-last-pushed-commit). - - -### Delete/remove arbitrary commit - -The same warning applies as above. Never do this if possible. - -```sh -$ git rebase --onto SHA1_OF_BAD_COMMIT^ SHA1_OF_BAD_COMMIT -$ git push -f [remote] [branch] -``` - - -### I want to delete a branch - -To delete a remote branch: - -```sh -(master)$ git push origin --delete my-branch -``` - -You can also do: - -```sh -(master)$ git push origin :my-branch -``` - -To delete a local branch: - -```sh -(master)$ git branch -D my-branch -``` - - -### Delete tag - -```sh -$ git tag -d -$ git push :refs/tags/ -``` - - -## Deleted Patch - -If someone has sent you a pull request on GitHub, but then deleted their original fork, you will be unable to clone their commits or to use `git am`. In such cases, it is best to manually look at their commits and copy them into a new branch on your local. Then, commit. - -After commiting, change the author of the previous commit. To do this, see how to [change author](#commit-wrong-author). Then, apply whatever changes needed on to, and make a new pull request. - - -## Check if all commits on a branch are merged - -To check if all commits on a branch are merged into another branch, you should diff between the heads (or any commits) of those branches: - -```sh -(master)$ git log --graph --left-right --cherry-pick --oneline HEAD...feature/120-on-scroll -``` - -This will tell you if any commits are in one but not the other, and will give you a list of any nonshared between the branches. Another option is to do this: - -```sh -(master)$ git log master ^feature/120-on-scroll --no-merges -``` ## I've no idea what I did wrong @@ -799,7 +830,7 @@ Using git reset it is then possible to change master back to the commit it was b * [git-workflow](https://github.com/asmeurer/git-workflow) - [Aaron Meurer](https://github.com/asmeurer)'s howto on using git to contribute to open source repositories * [GitHub as a workflow](http://hugogiraudel.com/2015/08/13/github-as-a-workflow/) - An interesting take on using GitHub as a workflow, particularly with empty PRs -## Scripts & Tools +## Scripts and Tools * [firstaidgit.io](http://firstaidgit.io/) A searchable selection of the most frequently asked Git questions * [git-extra-commands](https://github.com/unixorn/git-extra-commands) - a collection of useful extra git scripts