- Local VCS: Files stored on local machines
- Centralised VCS: A centralised system where the main repository is stored. Eg: CVS, SVN, Perforce
- Distributed VCS: Each client doesn't just check out the latest snapshot of the files; rather, they fully mirror the repository, including its full history. Eg: Git, Mercurial, Bazzar.
Other VCS like CVS, SVN, Bazzar stores delta changes after every commit(in each version of project), instead git stores snapshots of projects in every version(some file may have reference to previous, if that file was not updated)
- Git is fast as everything is local in git. While working other repository systems like SVN and CVS we need to be connected to the server to commit anything but with git we can commit locally also and when connected to the server we can push the changes.
- Also we can see the history of the project as it stores everything on local drive
Uses SHA-1(40 character string 0-9 and a-f) for integrity
- Modified: Locally modified
- Staged: Will be committed in next commit, using
git add
- Committed: When file is committed using
git commit
command
Git global variables, will be used in each commit
git config --global user.name "Hansraj Das"
git config --global user.email "[email protected]"
git config --global core.editor vim
git config --list
Two methods to get a git repository on our local machine
git init
git clone <url> <optional destination path>
- Tracked: Known to git, was present in last snapshot
- Untracked: Unknown to git, need to add this file in git
git status -s # Show short status
git status # Show detailed status
This command serves 2 purpose
- Adds any untracked file to git workspace
- Also adds already tracked and modified file to staging area so that it will be committed in next commit
git add <file(s)>
This command is used to see difference in repository
git diff # Diff of working(local) directory and staging area
git diff --staged # Diff of staged changes and last commit
git diff <commit-hash-1> <commit-hash-2> <file(s)>
git diff <commit-hash> <file(s)>
git diff <commit-hash> HEAD <file(s)>
git commit -a
git commit -am "<commit-message>"
git commit -m "<commit-message>" <file(s)>
Can be used to view to see logs/commit messages of a repository
git log # View detailed all log of project
git log <file/dir> # Logs specific file/dir
git log -n # Last n logs
git log -p # View all logs with diff (-p or --patch)
git log -p -n # View last n commits diffs with log
git log -p -n <file> # View last n commits diffs with log for specific file(s)
git log --stat # Log with number of lines inserted/deleted in files
git log <branch> # Show log for a specific branch(if not on that branch)
git log --graph # Show ASCII graph of branch and merge history
git log --pretty=<oneline|short|full|fuller>
git log --pretty=format:"%h by %an, %ar: %s"
# %h: Short commit hash
# %an: User name
# %ar: How much time ago
# %s: Commit message
# Other options can be used...
git log --grep="<search in commit msg>"
git log -S "<code diff>" # Searches diff
Any complex query is possible
git log --author=hansraj --since="2008-10-01” --before=”2008-11-01"
# --since and --until: Time limit logs
# --no-merges: Without merge commits
In git HEAD
is pointer to the local branch(like master, etc...) we are currently on
git log --oneline --decorate # See where HEAD is pointing to and other details
git log --oneline --decorate --graph --all # Show logs with diversion history(where branches diverged)
Branch is a new pointer to a commit
git branch # List branch names
git branch -v # List last commits in each branch
git branch --merged # List branches merged to current branch
git branch --no-merged # List branches not merged to current branch
git checkout -b <new-branch> # Create and switches to new branch from head of current branch
git branch <new-branch> # Create a new branch, don't switch to that branch
git checkout <branch-name> # Switch to other branch
Creates and switches to new branch from current branch not from HEAD(latest) but from some specific previous commit on current branch. This is useful for undoing things
git checkout -b <new-branch> <commit-hash>
Start a new local branch serverfix
from origin/serverfix
, we can have different local branch name than on remote
git checkout -b serverfix origin/serverfix
Create local branch with the same branch name as on remote
git checkout --track origin/serverfix
git branch -d <branch-name>
Note: Branch that is not yet merged to current will give an error while deleting with -d flag. We can delete those branches forcefully
git branch -D <branch-name>
This will not create a new commit log but update the last commit with this one, we modify files and commit messages in this re-commit. We end up with a single commit - the second commit replaces the results of the first
git commit --amend
git commit --amend -m "Updated commit msg"
git checkout -- . # All changes
git checkout -- <file(s)> # For specific files
git checkout <commit-hash> -- <file(s)>
git checkout <commit-hash>~1 -- <file(s)>
If we don't want to commit changes done in a file but accidentally added this file to staging area, this command can be used to unstage this file
git reset HEAD <file/dir>
Moves head of file(s) to commit-hash
and changes from commit-hash
to old HEAD to staging head(shown as green in status)
git reset --soft <commit-hash> <file(s)>
Moves head of file(s) to commit-hash
and changes from commit-hash
to old HEAD to un-staging head(shown as red in status)
git reset --mixed <commit-hash> <file(s)>
Totally removes all commits and moves head to given commit hash
git reset --hard <commit-hash> <file(s)>
Note: Git reset command also removes commit logs so not recommended
git revert HEAD # Revert last commit
git revert HEAD~n # Revert last nth commits
Revert all changes done from commit-hash-1
to commit-hash-2
(excluding commit-hash-1
)
git revert <commit-hash-1>..<commit-hash-2>
Note: revert
creates new revert commits for each commit reverted
On git clone <url>
, apart from local master
branch a remote branch is also created called origin/master
where origin
is default remote name
Lists remotes configured with URL, git clone
command adds origin
remote implicitly
git remote -v
Lists which tracking branch is setup on each local branch
git branch -vv
git remote add <shortname> <url> # Add remote explicitly
git branch -u origin/serverfix # Set up upstream of the current branch to origin/serverfix
git remote show <remote>
git remote rename <existing remote> <new remote>
git remote rm <remote-name>
git remote set-url origin https://github.com/user/repo2.git # Change the 'origin' remote's URL
Fetches new changes from remote to local working dir and moves origin/master to its new position. fetch
only fetches the changes and does not merges it to local branch
git fetch # Fetch changes from default remote
git fetch <remote-name> # Fetch changes from given remote-name
Automatically fetch and then merge(pull uses merge strategy not rebase) the remote branch into current local branch. Git clone automatically sets the local master branch to track the remote master branch
git pull
git push # Push current branch changes to default upstream(like origin)
git push <remote> <branch> # Push current branch changes to upstream, to specific branch on a specific remote
git push origin --delete serverfix # Delete reference to `serverfix` on remote
git tag # List all tags
git tag -l "1.1.0.*" # List all tags which has 1.1.0*
Permanent tag, stores a lot of information, use -a
flag
git tag -a v1.0 -m "My first tag" # Create annotated tag
git show v1.0 # Show details of tag v1.0
Stores less info, don’t use any flag
git tag v1.0-lw # Create a lightweight tag
git show v1.0-lw # Show tag info
Create a tag on given commit hash
git tag -a v1.2 <commit-hash> -m "<Tag msg>"
By default, tags are not shared to the server with git push
, we have share tags explicitly
git push <remote> <tagname> # Push a specific tag to server
git push <remote> --tags # Share all tags created to server
Checks out code from given tag
git checkout <tagname>
As we cannot commit on tag we will have to create a branch from tag to commit changes
git checkout -b <branch-name> <tagname>
git tag -d <tagname>
Create an alias of git simple/complex commands
git config --global alias.br branch # To create alias of `git branch` to `git br`
git config --global alias.last 'log -1 HEAD' # Get last commit info with `git last`
Merges the changes from branch-name
to current branch we are currently in
git merge <branch-name>
- If both branches have common ancestors, merge is done in fast forward way as it simply changes the commit pointer of current branch to
branch-name
commit pointer - If both branches don't have common ancestor, three-way merge is done which creates a new commit to which current branch now points. This new commit is also called as merge commit and has 2 parents(one where the current branch was initially pointing and other where
branch-name
was pointing)
- We may get merge conflict when the same line is updated in current and branch from which we are merging, gives error
Automatic merging failed
. Files not merged can be seen usinggit status
- In this case we have to open each file and resolve conflicts, when resolved run
git add <file-name(s)>
to marked as conflict has been resolved and can be committed git mergetool
Opens the diff(local and other branch file) in an editor to resolve conflict(s)
git rebase master # Rebases current branch with the changes done in master
- Both rebase and merge command works to sync multiple branches. Rebasing is preferred on remote branches instead of merge to have cleaner log history
- Rebasing replays(takes diff and applies) changes from one line of work onto another in the order they were introduced, whereas merging takes the endpoints and merges them together
- Rebasing first moves pointer of current branch to new reference then creates new commits of the changes done in current branch so it is preferred in local branch and not on shared branches like master
- Below command - Take the client branch, figure out the patches since it diverged from the server branch, and replay these patches in the client branch as if it was based directly off the master branch instead. Ultimately updates the client branch
git rebase --onto master server client
Used to merge specific commits only, not whole branch
git cherry-pick <commit-hash> # Merge changes committed in `commit-hash` to current branch
- Book: https://git-scm.com/book/en/v2
- git cherry-pick: https://w3guy.com/git-merge-commit-from-another-branch/
- Merge vs rebasing: https://www.atlassian.com/git/tutorials/merging-vs-rebasing