Git Handbook






4.25/5 (3 votes)
Git for daily usage
Introduction
I won't dive into the history of version control or stuff like that. In this article, I aimed to create a quick how-to document for Git. By the way, if you are new to Git, I describe it as 'spaceship over a file system with a time machine'. You can freeze time in any space, you can travel to those frozen points and live again from that point of time. I think I am about to end up with parallel universes and related paradoxes. Still, I want to live in Git.
Background
There exist two important points to keep in mind when using Git.
Three states of a file
- Modified (working on the file in working directory)
- Staged (ready-to-commit in staging area)
- Committed (frozen in repository)
Bold words above are common terminology in Git. Working directory is the git-tracked directory. When you create a file in working directory, it is actually marked as untracked by Git. Your untracked and modified files will never go into the repository unless you take them to the staging area explicitly. After you stage all your work, you can commit them into the repository, which means you freeze the file system at that point of time.
Where is the HEAD?
HEAD is a special pointer in Git system. It can be thought as a pointer to the place where you are about to commit. When you tell Git to commit, HEAD shows the time point to freeze your current space. Always know where your HEAD is while working within Git.
Last point before starting. Remember to visit help when you are in doubt.
$git help <git_command>
Content
- Working with files
- Start a new repository in the current directory
- Stage a file (prepare for commit)
- Commit changes (create a time point to jump later)
- Remove a file
- Take back this delete
- Add a file to ignore list
- Rename a file
- Add changes to the last commit (in case of you forget some simple things)
- Working with directories
- Adding a directory and a file
- Delete a directory
- Undo it
- Rename a directory
- Add a directory to ignore list
- Commits
- Branching
- Create a branch and work on it
- Merge to main branch
- Find difference between branches
- Another difference example
- Rebasing
- Remote repositories
- Clone a remote repository
- Fetch from remote
- Pull from remote
- Push to remote
- Push to a remote branch
- Find difference with a remote
- Stashing
Using Git
Working with files
Start a new repository in the current directory || to_content
$ git init Initialized empty Git repository in /cygdrive/d/projects/test/.git/ ### 'status' command shows the current state of your work ### and mostly tells you how to proceed. ### in this case, there is nothing to commit and it tells you that you ### can use 'add' command to track a file. $ git status # On branch master # # Initial commit # nothing to commit (create/copy files and use "git add" to track)
Stage a file (prepare for commit) || to_content
### create a file $ touch 1.c ### see what happens $ git status # On branch master # # Initial commit # # Untracked files: # (use "git add <file>..." to include in what will be committed) # # 1.c nothing added to commit but untracked files present (use "git add" to track) ### we have an untracked file, and we can track it by using 'add' command as ### it says $ git add 1.c ### check status $ git status # On branch master # # Initial commit # # Changes to be committed: # (use "git rm --cached <file>..." to unstage) # # new file: 1.c # ### 1.c is now staged (can be committed into the repo). ### if you like, you can take it out of the staging area (which makes it untracked) ### by using 'rm --cached' command as it says.
Commit changes (create a time point to jump later) || to_content
### commit the staged files with a commit note $ git commit -m "first file added" [master (root-commit) 55b349c] first file added 0 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 1.c ### see the status $ git status # On branch master nothing to commit (working directory clean)
### 'rm' command does two things: ### 1- removes file from working directory, ### 2- stages this change (makes ready to commit) $ git rm 1.c rm '1.c' $ git status # On branch master # Changes to be committed: # (use "git reset HEAD <file>..." to unstage) # # deleted: 1.c #
Take back this delete || to_content
### reset HEAD for this file (unstage this change) $ git reset HEAD 1.c Unstaged changes after reset: D 1.c ### now this change is not staged. $ git status # On branch master # Changes not staged for commit: # (use "git add/rm <file>..." to update what will be committed) # (use "git checkout -- <file>..." to discard changes in working directory) # # deleted: 1.c # no changes added to commit (use "git add" and/or "git commit -a") ### call back 1.c from the last commit point to the working directory $ git checkout 1.c $ git status # On branch master nothing to commit (working directory clean)
Add a file to ignore list || to_content
### create a file $ touch 2.out ### create '.gitignore' special file ### this file shows which patterns will not be tracked by Git. $ echo .gitignore > .gitignore $ echo 2.out >> .gitignore ### git doesn't see '2.out' anymore $ git status # On branch master nothing to commit (working directory clean)
### use 'mv' command $ git mv 1.c 2.c $ git status # On branch master # Changes to be committed: # (use "git reset HEAD <file>..." to unstage) # # renamed: 1.c -> 2.c #
Add changes to the last commit (in case of you forget some simple things) || to_content
### create some files $ touch 2.c 3.c ### add them to the staging area $ git add . $ git status # On branch master # Changes to be committed: # (use "git reset HEAD <file>..." to unstage) # # new file: 2.c # new file: 3.c # ### commit changes $ git commit -m "new files added" [master 830d12c] new files added 0 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 2.c create mode 100644 3.c ### oops, forgotten comments in 1.c $ echo aa > 1.c ### 1.c is modified $ git status # On branch master # Changes not staged for commit: # (use "git add <file>..." to update what will be committed) # (use "git checkout -- <file>..." to discard changes in working directory) # # modified: 1.c # no changes added to commit (use "git add" and/or "git commit -a") ### add last changes to the staging area $ git add . ### 'commit --amend' to append those changes to the last commit $ git commit --amend [master d1941e8] new files added 1 files changed, 1 insertions(+), 0 deletions(-) create mode 100644 2.c create mode 100644 3.c
Working with directories
Adding a directory and a file || to_content
### create a directory and a file in it $ mkdir dir1 $ touch dir1/11.c ### see status $ git status # On branch master # Untracked files: # (use "git add <file>..." to include in what will be committed) # # dir1/ nothing added to commit but untracked files present (use "git add" to track) ### add changes to the staging area $ git add . $ git status # On branch master # Changes to be committed: # (use "git reset HEAD <file>..." to unstage) # # new file: dir1/11.c # ### commit changes $ git commit -m "dir1 added" [master bc39a14] dir1 added 0 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 dir1/11.c
Delete a directory || to_content
$ git rm -r dir1 rm 'dir1/11.c' $ git status # On branch master # Changes to be committed: # (use "git reset HEAD <file>..." to unstage) # # deleted: dir1/11.c #
$ git reset HEAD dir1 Unstaged changes after reset: D dir1/11.c $ git checkout dir1 $ git status # On branch master nothing to commit (working directory clean)
Rename a directory || to_content
$ git mv dir1 dir2 $ git status # On branch master # Changes to be committed: # (use "git reset HEAD <file>..." to unstage) # # renamed: dir1/11.c -> dir2/11.c #
Add a directory to ignore list || to_content
$ mkdir dir2 $ touch dir2/21.c ### caution: adding 'dir2/' makes a recursive description. ### all 'dir2/'s will be ignored in every directory. $ echo "dir2/" >> .gitignore $ git status # On branch master nothing to commit (working directory clean)
Commits
See commit history || to_content
### every commit is pointed by its checksum calculated over some statistics of that commit. ### checksum has 40 hex chars, output of SHA-1 algorithm $ git log commit d1941e8a7f76067c4ea300d10ca6ad18fa8f6264 Author: ozanoner Date: Mon Mar 31 21:02:59 2014 +0300 new files added commit 55b349ca5142282124bdef0ebb8cf9b46e1bb96f Author: ozanoner Date: Mon Mar 31 20:39:40 2014 +0300 first file added
### list commits one-line, reverse ordered by its date $ git log --pretty=oneline d1941e8a7f76067c4ea300d10ca6ad18fa8f6264 new files added 55b349ca5142282124bdef0ebb8cf9b46e1bb96f first file added ### tag a commit $ git tag v0.1 55b349ca5142282124bdef0ebb8cf9b46e1bb96f ### tag latest commit $ git tag v0.2 ### list tags $ git tag v0.1 v0.2 ### list tags and commit messages $ git tag -n v0.1 first file added v0.2 new files added
Show commit with its tag || to_content
### shows commit (checksum, author, date, message, changes) tagged as 'v0.2' $ git show v0.2 commit d1941e8a7f76067c4ea300d10ca6ad18fa8f6264 Author: ozanoner Date: Mon Mar 31 21:02:59 2014 +0300 new files added diff --git a/1.c b/1.c index e69de29..e61ef7b 100644 --- a/1.c +++ b/1.c @@ -0,0 +1 @@ +aa diff --git a/2.c b/2.c new file mode 100644 index 0000000..e69de29 diff --git a/3.c b/3.c new file mode 100644 index 0000000..e69de29
### delete tag v0.2 (nothing with commit) $ git tag -d v0.2 Deleted tag 'v0.2' (was d1941e8) ### list tags with commit messages $ git tag -n v0.1 first file added
Branching
Create a branch and work on it || to_content
### create a new branch named 'test_branch' from the current branch $ git branch test_branch ### make it active branch ### HEAD is on 'test_branch' now $ git checkout test_branch Switched to branch 'test_branch' ### edit 1.c version in 'test_branch' $ echo bb >> 1.c ### add changes to the staging area and commit them ('commit -a') $ git commit -am '1.c edited in new branch' ### show branches $ git branch -v master f694fb8 first commit * test_branch 44e91ae 1.c edited in new branch
Merge to main branch ('master') and delete temporary branch ('test_branch') || to_content
### make 'master' active branch (ie. HEAD moved to 'test_branch') $ git checkout master Switched to branch 'master' ### merge 'test_branch' onto 'master' $ git merge test_branch Updating f694fb8..44e91ae Fast-forward 1.c | 1 + 1 files changed, 1 insertions(+), 0 deletions(-) ### check logs to see what happened $ git log commit 44e91aea6ee69b874e1cbb2e73390fb5e0eb68bb Author: ozanoner Date: Wed Apr 2 15:34:28 2014 +0300 1.c edited in new branch commit f694fb8f1c30c9564be9a8bf32392dc84b4559a8 Author: ozanoner Date: Wed Apr 2 15:32:14 2014 +0300 first commit $ git status # On branch master nothing to commit (working directory clean) ### we are done with 'test_branch'. delete it $ git branch -d test_branch Deleted branch test_branch (was 44e91ae).
Find difference between branches || to_content
### create 'new_dev' and move HEAD to it. $ git checkout -b new_dev Switched to a new branch 'new_dev' ### edit 1.c in 'new_dev' $ echo dd >> 1.c ### stage and commit $ git commit -am 'modified in new_dev' [new_dev 385f6a9] modified in new_dev 1 files changed, 1 insertions(+), 0 deletions(-) ### move HEAD to 'master' branch $ git checkout master Switched to branch 'master' ### compare 'new_dev' and the current branch ('master') $ git diff new_dev diff --git a/1.c b/1.c index 955bebf..3b7dd8b 100644 --- a/1.c +++ b/1.c @@ -1,4 +1,3 @@ aa bb cc -dd ### compare file versions on different branches $ git diff master:1.c new_dev:1.c diff --git a/master:1.c b/new_dev:1.c index 3b7dd8b..955bebf 100644 --- a/master:1.c +++ b/new_dev:1.c @@ -1,3 +1,4 @@ aa bb cc +dd
Another difference example || to_content
### edit 2.c in 'master' $ echo aa > 2.c ### and stage changes $ git add . ### this change is included in comparison since it is in the staging area. $ git diff new_dev diff --git a/1.c b/1.c index 955bebf..3b7dd8b 100644 --- a/1.c +++ b/1.c @@ -1,4 +1,3 @@ aa bb cc -dd diff --git a/2.c b/2.c new file mode 100644 index 0000000..e61ef7b --- /dev/null +++ b/2.c @@ -0,0 +1 @@ +aa ### change to 2.c is not visible by the latest commit in branch 'master' $ git diff new_dev master diff --git a/1.c b/1.c index 955bebf..3b7dd8b 100644 --- a/1.c +++ b/1.c @@ -1,4 +1,3 @@ aa bb cc -dd ### merge 'master' and 'new_dev' $ git merge new_dev Updating 97d650c..385f6a9 Fast-forward 1.c | 1 + 1 files changed, 1 insertions(+), 0 deletions(-) ### no difference between 'master' and 'new_dev' $ git diff master new_dev ### delete 'new_dev' branch $ git branch -d new_dev Deleted branch new_dev (was 385f6a9).
Rebasing (appending last work from a different branch) || to_content
### create and switch to 'testing' branch $ git checkout -b testing Switched to a new branch 'testing' ### edit 1.c in 'testing' $ echo ccc >> 1.c ### stage and commit $ git commit -am '1.c corrected' [testing 0c8e0a2] 1.c corrected 1 files changed, 1 insertions(+), 0 deletions(-) ### append it to 'master' $ git rebase master Current branch testing is up to date. ### switch to 'master' $ git checkout master Switched to branch 'master' ### this 'merge' command just re-aligns 'master' $ git merge testing Updating 1d5b72e..0c8e0a2 Fast-forward 1.c | 1 + 1 files changed, 1 insertions(+), 0 deletions(-) $ cat 1.c aa bb ccc ### delete 'testing' branch $ git branch -d testing Deleted branch testing (was 0c8e0a2)
Remote repositories
Clone a remote repository || to_content
### clone remote repository in the current directory. ### that means remote repo is duplicated in local directory as 'master' branch. ### note that another branch created as 'origin/master' in local repo ### representing remote branch $ git clone https://github.com/ozanoner/test . Cloning into '.'... remote: Counting objects: 5, done. remote: Compressing objects: 100% (2/2), done. remote: Total 5 (delta 0), reused 3 (delta 0) Unpacking objects: 100% (5/5), done. ### see log for this new repo $ git log commit 44a94d529c9be2920e62400ee570ebdb23c101fd Author: ozanoner Date: Tue Apr 1 15:15:01 2014 +0300 Delete README.txt commit 4cf94f8556d45e258cc127b891c1a6add1f1617c Author: ozanoner Date: Tue Apr 1 15:13:44 2014 +0300 first commit
Fetch from remote repo (refresh origin/master || to_content
### list remote repos $ git remote -v origin https://github.com/ozanoner/test (fetch) origin https://github.com/ozanoner/test (push) ### fetch from remote repo into local representation (origin/master) $ git fetch origin remote: Counting objects: 4, done. remote: Total 3 (delta 0), reused 0 (delta 0) Unpacking objects: 100% (3/3), done. From https://github.com/ozanoner/test 44a94d5..1ea2bab master -> origin/master ### no change in 'master' yet $ git log commit 44a94d529c9be2920e62400ee570ebdb23c101fd Author: ozanoner Date: Tue Apr 1 15:15:01 2014 +0300 Delete README.txt commit 4cf94f8556d45e258cc127b891c1a6add1f1617c Author: ozanoner Date: Tue Apr 1 15:13:44 2014 +0300 first commit ### merge 'master' and 'origin/master' $ git merge origin/master Updating 44a94d5..1ea2bab Fast-forward README.md | 1 + 1 files changed, 1 insertions(+), 0 deletions(-) create mode 100644 README.md ### changes in remote repo is now merged into 'master' ### README.md file is added. $ git log commit 1ea2babd342e1432626d6536afbcce320005b643 Author: ozanoner Date: Thu Apr 3 10:39:09 2014 +0300 Create README.md commit 44a94d529c9be2920e62400ee570ebdb23c101fd Author: ozanoner Date: Tue Apr 1 15:15:01 2014 +0300 Delete README.txt commit 4cf94f8556d45e258cc127b891c1a6add1f1617c Author: ozanoner Date: Tue Apr 1 15:13:44 2014 +0300 first commit
Pull from remote (fetch into 'origin/master' and merge onto 'master') || to_content
### pull command (fetch&merge) $ git pull origin remote: Counting objects: 4, done. remote: Compressing objects: 100% (2/2), done. remote: Total 3 (delta 0), reused 0 (delta 0) Unpacking objects: 100% (3/3), done. From https://github.com/ozanoner/test 1ea2bab..b456638 master -> origin/master Updating 1ea2bab..b456638 Fast-forward 1.c | 1 + 1 files changed, 1 insertions(+), 0 deletions(-) create mode 100644 1.c ### see last 2 logs $ git log -2 commit b456638c54a61595c1f112cdb13ac5574aaba58c Author: ozanoner Date: Thu Apr 3 10:43:30 2014 +0300 Create 1.c commit 1ea2babd342e1432626d6536afbcce320005b643 Author: ozanoner Date: Thu Apr 3 10:39:09 2014 +0300 Create README.md
Push to remote (send changes to remote repository) || to_content
### create a file and commit changes $ touch 2.c $ git commit -am '2.c added' [master 50b88d7] 2.c added 0 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 2.c ### push changes to remote 'origin' ### as from local 'master' branch to remote 'master' branch $ git push origin master:master Username for 'https://github.com': Password for 'https://ozanoner@github.com': Counting objects: 4, done. Delta compression using up to 8 threads. Compressing objects: 100% (2/2), done. Writing objects: 100% (3/3), 289 bytes, done. Total 3 (delta 0), reused 0 (delta 0) To https://github.com/ozanoner/test b456638..50b88d7 master -> master
Push to a remote branch || to_content
### create and switch to branch 'testing' $ git checkout -b testing Switched to a new branch 'testing' ### create a file and commit changes $ echo aa > 2.c $ git commit -am 'testing 2.c' [testing 7be7133] testing 2.c 1 files changed, 1 insertions(+), 0 deletions(-) ### push changes to remote 'origin' ### from local branch 'testing' to remote branch 'testing' $ git push origin testing:testing Username for 'https://github.com': Password for 'https://ozanoner@github.com': Counting objects: 3, done. Delta compression using up to 8 threads. Compressing objects: 100% (2/2), done. Writing objects: 100% (2/2), 219 bytes, done. Total 2 (delta 1), reused 0 (delta 0) To https://github.com/ozanoner/test 50b88d7..7be7133 testing -> testing
Find difference with a remote repo || to_content
### first fetch into local 'origin/master' branch $ git fetch origin remote: Counting objects: 1, done. remote: Total 1 (delta 0), reused 0 (delta 0) Unpacking objects: 100% (1/1), done. From https://github.com/ozanoner/test 50b88d7..b26e2af master -> origin/master ### then see the difference $ git diff origin diff --git a/2.c b/2.c index e61ef7b..e69de29 100644 --- a/2.c +++ b/2.c @@ -1 +0,0 @@ -aa
Stashing (saving state temporarily)
### create a branch (dont switch yet) $ git branch testing ### modify file in the current branch $ echo cc >> 1.c $ git status # On branch master # Changes not staged for commit: # (use "git add <file>..." to update what will be committed) # (use "git checkout -- <file>..." to discard changes in working directory) # # modified: 1.c # no changes added to commit (use "git add" and/or "git commit -a") ### want to switch branch 'testing' but need to save current state without commit ### solution is stashing $ git stash Saved working directory and index state WIP on master: e01a00f Update 1.c HEAD is now at e01a00f Update 1.c ### move HEAD to 'testing' branch $ git checkout testing Switched to branch 'testing' ### done with 'testing', switch to 'master' $ git checkout master Switched to branch 'master' ### oops, status tells us no change $ git status # On branch master nothing to commit (working directory clean) ### forgotten to apply temporary versions, therefore apply stash $ git stash apply # On branch master # Changes not staged for commit: # (use "git add <file>..." to update what will be committed) # (use "git checkout -- <file>..." to discard changes in working directory) # # modified: 1.c # no changes added to commit (use "git add" and/or "git commit -a") ### done with that stash, drop it $ git stash drop Dropped refs/stash@{0} (e62a20cd9ff4053dfcd64e26d038955f2274de54)
|| to_content
References
No need to say but:
https://www.google.com.tr/#q=git+reference+book
and this book contains everything you may need: