1. Checkout
The git checkout
moves the HEAD
ref pointer to a specified commit. To demonstrate this, consider the following example:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
mkdir remote_repose mkdir repos && cd repos git init git init --bare ../remote_repose/ git remote add origin ../remote_repose/ touch A.txt git add -A git commit -a -m 'A Added' git push --set-upstream origin master touch B.txt git add -A git commit -a -m 'B Added' git push touch C.txt git add -A git commit -a -m 'C Added' git push touch D.txt git add -A git commit -a -m 'D Added' git push |
Now you can change the HEAD
with:
1 |
git checkout <commit-id> |
or
1 |
git checkout HEAD~<number> |
you can find all commits again by:
1 |
git log --all |
For instance:
1 |
git checkout HEAD~2 |
1 |
gitk --all |
1.2 Detached HEAD
Any checkout of a commit that is not the name of one of your branches will get you a detached HEAD
. When HEAD is detached, commits work like normal, except no named branch, gets updated. (You can think of this as an anonymous branch.)
1.3 Cleaning up git environment and rollbacking local changes
Once you started working on your local copy you might mess everything up and need to clean up or roll back changes for some files, you can use git checkout and git clean
to rollback changes for a particular file:
1 |
git checkout <filename> |
to reset or revert a file to a specific revision
1 |
git checkout <commit-hash> -- file/to/restore |
to rollback changes for the entire local copy while keeping added files:
1 |
git checkout . |
If you just want to remove the file and directories that have been added but not staged:
1 |
git clean -d –dry-run -i |
-d
Remove untracked directories in addition to untracked files.
-dry-run
Don’t actually remove anything, just show what would be done.
-i
Show what would be done and clean files interactively. See “Interactive mode” for details.
This will create a new branch and switch to that:
1 |
git chekcout -b <branch name> |
-f: clean untracked files
-d: also remove directories
-x: remove ignored as well as non-ignored files
1 |
git clean -xfd |
2. Git reset
How to undo a commit in Git when you haven’t pushed it yet? The answer is git reset
. The usage of git reset is to undo changes that haven’t been shared with anyone else, for instance when you’ve started working on a feature. reset has three options, hard and soft, and mixed.
1 |
git reset --hard/ --soft/ --mixed <COMMIT> |
1) Mixed: This is the default action. Resets the index1 but not the working tree2 (i.e., the changed files are preserved but not marked for commit) and reports what has not been updated.
2) Soft: Does not touch the index file or the working tree at all, but resets the head to <commit>. This leaves all your changed files “Changes to be committed”
3) Hard: This option will reset the index and working tree. Any changes to tracked files in the working tree since <commit> are discarded.
1 The git “index” is where you place files you want to commit to the git repository. Some names you may have heard:
- Index
- Cache
- Directory cache
- Current directory cache
- Staging area
- Staged files
Files in the git index don’t get committed to the repository until you use the git commit command.
2 Working tree is what is actually in the files that you are currently working on:
1 |
git ls-files -s |
git ls-tree only works with git refs, e.g.
1 |
git ls-tree HEAD |
Examples:
1 2 3 |
git reset --hard f414f31 git reset --soft HEAD@{1} git reset --soft HEAD~2 |
You can undo your reset by
1 |
git reset HEAD@{1} |
Since after your first reset your previous HEAD is at one commit before the current one.
git log
will be exactly the same as before, but git relog
will show you that you have reset the HEAD.
Refs: [1]
2.1 A Complete Example
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
mkdir remote_repose mkdir repos && cd repos git init git init --bare ../remote_repose/ git remote add origin ../remote_repose/ touch A.txt git add -A git commit -a -m 'A Added' touch B.txt git add -A git commit -a -m 'B Added' git push --set-upstream origin master touch C.txt git add -A git commit -a -m 'C Added' touch D.txt git add -A git commit -a -m 'D Added' |
Now if we run the followings:
1 |
git reset HEAD~1 |
Git permanently deletes such commits (D Added) after 30 days. You can recover that by:
1 |
git reset HEAD@{1} |
HEAD~2
: 2 commits older than HEADHEAD^2
: the second parent of HEAD, if HEAD was a merge, otherwise illegalHEAD@{2}
: refers to the 3rd listing in the overview ofgit reflog
HEAD~~
: 2 commits older than HEADHEAD^^
: 2 commits older than HEAD
The git reflog command records a chronological history of everything you have done in your local repository. Its full output might look like this:
1 2 3 4 |
f5e1928 HEAD@{0}: commit: D Added c1b9dc0 HEAD@{1}: commit: C Added 7e365d8 HEAD@{2}: commit: B Added ab0b179 HEAD@{3}: commit (initial): A Added |
C.txt and D.txt will remain (soft)
1 |
git reset --hard HEAD~2 |
C.txt and D.txt will be deleted.
To see which files have been added and their status:
1 2 |
git ls-files git status |
Finally, lets’ push changes by:
1 2 |
git push -f git push --force |
3. git revert
How to undo a push in Git when you have pushed your commits? The answer is Git revert.
This command has the ‘undo’ type (not a traditional undo operation). It determines how to reverse the modifications made by the commit and adds a new commit with the resulting inverted content, rather than removing the commit from the project history. Due to the integrity of your revision history and the need for trustworthy collaboration, this keeps Git from losing its history.
Examples:
1 2 |
git revert 9c45ce3b81ff6cf5219c31b490bffbc7e894e060..HEAD git revert <hash> or git revert <hash1>..<hash2> |
3.1 A Complete Example
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
mkdir remote_repose mkdir repos && cd repos git init git init --bare ../remote_repose/ git remote add origin ../remote_repose/ touch A.txt git add -A git commit -a -m 'A Added' git push --set-upstream origin master touch B1.txt touch B2.txt git add -A git commit -a -m 'B1 & B2 Added' git push touch C.txt git add -A git commit -a -m 'C Added' git push touch D.txt git add -A git commit -a -m 'D Added' git push date >B1.txt git add -A git commit -a -m 'B1 updated' git push |
Now, let’s revert the commit that added the B1, B2. As you can see, we have modified B1 in the last commit, so we would have a conflict:
1 |
git revert a6d6ec0a7ca44f05306171ee486920984825ec5f |
to resolve the conflict:
1 |
git mergetool |
4. amend
This will fix your most recent commit message
Example
1 |
git commit --amend -m "an updated commit message" |
some important notes:
1 2 3 |
git add -A stages all changes git add . stages new files and modifications, without deletions git add -u stages modifications and deletions, without new files |
git add -A
is equivalent to
1 2 |
git add . git add -u . |
Searching for a file in all branches
1 |
% git log --all -- '**/<file-name>' |
Un-stage a file:
1 |
git rm –cached <file-name> |
Clean everything that has been added to the repository and has not been staged:
1 |
git clean -xdf |