Git stores content in three "areas":
Working Directory -> Staging Area (index) - > Git Repository
Git References (so called "treeish") are a way to access specyfic commits. It can be accessed with:
- SHA-1 Hash (full or 6-7 characters which is usually enough)
- Branches - latest commit on a specyfic branch
- Tags
- HEAD - latest commit on current branch
- Ancestry Refs: HEAD HEAD~ HEAD
2 HEAD3
git ls-tree HEAD
- list the files in the repository at particular time, here HEAD
Configuration is set on three levels: system, global (user), local (repository):
git config --system
: machine configuration
git config --global
: user level configuration
git config
: project level configuration
Sample & basic configuration:
``git config --global user.name "Paweł Waszczyński"```
``git config --global user.email "waszczynski@gmail.com"```
git config --global color.ui true
git config --global core.editor "'C:/Program Files (x86)/Notepad++/notepad++.exe' -multiInst -notabbar -nosession -noPlugin"
git config --global aliag.<aliasname> "<command>"
E.g.
Modified log command that gives some visual info about commits:
git config --global alias.lgas "log --graph --oneline --all --decorate --max-count 10"
git lga
* d060744 (HEAD -master) Fourth
| * 06f748e (feature) Commit on feature branch
|/
* 7353cf1 Second commit
* a96544f First commit
* 36fd579 (origin/master, origin/HEAD) Initial commit
git init
- creates empty repository with hidden .get folder (only one - no nested .git folders)
Git’s notion of Staging Index - set of changes to be updated with next commit.
To add the file to staging area issue:
git add filename
: start tracking new file or add changes of already tracked file to staging areagit add --u
: add to staging area files already in repogit add --A
: add all files, including new
TIP : git add -i
enters interactive mode that enables "partial" commits (e.g. stage parts of the file).
Git records changes in file's content.
Some changes in the file's content can be in staging area (will be shipped with next commit), and other may not.
git status
- shows difference between working copy, **staging index ** and repository
Because git has three "areas" (working copy, staging index & repository) there're three ways to compare changes:
-
git diff
: shows the changes between the working directory and the index. This shows what has been changed, but is not staged for a commit. -
git diff --staged
: shows the changes between the index and the HEAD (which is the last commit on the branch). This shows what has been added to the index and staged for a commit. -
git diff HEAD
: shows all the changes between the working directory and HEAD (which includes changes in the index). This shows all the changes since the last commit, whether or not they have been staged for commit or not.
Add --name-only
flag to list only files with changes: git diff --name-only --cached
.
To to diff for one file, use filename as parameter e.g.:
git diff README.MD
More advanced usage:
git diff <treeish1> <treeish2> filename
- e.g.git diff HEAD~ HEAD README.md
shows changes in the file between HEAD and HEAD-1git diff <treeish1>..<treeish2>
- e.g.git diff 36fd579..HEAD
shows all changes between two commits (36fd579 and HEAD)git diff <branchA> <branchB>
- if both arg are branch names we get differences between themgit diff --stat --summary <treeish1>..<treeish2>
- show some stats & summarygit diff -w
- ignore whitespace
git log
: simply shows historygit log --since
(or --after etc, many options are available)git log sha1..sha2
- specify a rangegit log sha1.. --author username filename
- gives logs that affect a file since sha1 and made by usernamegit log --pretty="%h, %cn, %cr"
- custom log reportgit log -n
: limits to n number of commitsgit log --grep="message"
: search with regexgitk
- graphical tool to view history (shipped with git)
By default git log
shows log only for current branch.
git log --all
: view log from all branches use
--online
switch reduces log info to one:
> git log --oneline --all
3da6a59 Update readme
5783114 Clean up of readme
5bec871 Merged experimental
313b94d Experimental checkin
Each commit has a hash which is calculated with this formula:
sha1(
meta data
commit message
commiter
commit date
author
authoring date
Hash-Of-Entire-Working-Directory
)
git commit
- opens up text editor for supplying commit messagegit commit -a
- commits changes & automatically stage all tracked, modified files before the commit (the same asgit add
+git commit
)git commit -m "commit message"
- enables adding commit message as string after-m
TIP: To change/amend message/content of last commit, use:
git commit --amend -o -m "New commit message"
- changes only message (-o)git commit --amend -m "New commit message"
- changes previous commit by also commiting currently staged changes + modifies message. Useful when you forgot to add include something in previous commit
git branch
- lists branchesgit branch -a
: lists all branches, including remote onesgit branch -r
: lists only remote branches
git branch branch-name
- creates new branch, but does not switch repo to that branch yetgit branch branchname <treeish>
- creates a branch from particular commitgit branch --move oldname newname
- renames branch
git checkout -b branch-name
- create & switch to branch. Git allows to change branches with changes in index & working directory, provided they don't cause overridesgit checkout branch-name
- switch to branch
There're two ways to merge changes: merge & rebase.
git merge <branch-name>
: merges changes from branch-name into current branch.
Merge creates additional commit:
* 0017058 (HEAD -> master) Merge branch 'feature'
|\
| * befa7a0 (feature) Line four commit
| * 46555f0 Line three commit
* | b8a1df9 Title updated
|/
* a756e66 Line two commit
* b6be659 Line one commit
* 36fd579 (origin/master, origin/HEAD) Initial commit
TIP: how to check if branch is merged? git branch --merged
lists branches that are included in the current branch.
git rebase branchname
- tries to replay changes made to current branch to branchname
Why rebase:
- keeps history cleaner & linear (no additional merge commits)
Before:
* 6eb6e94 (HEAD -> master) Title updated
| * 2c8811f (feature) Line four commit
| * 1d4235c Line three commit
|/
* 9eb041a Line two commit
* 8fee707 Line one commit
* 36fd579 (origin/master, origin/HEAD) Initial commit
After git rebase feature
:
> git rebase feature
First, rewinding head to replay your work on top of it...
Applying: Title updated
And graph:
> git lga
* f6e1f04 (HEAD -> master) Title updated
* 2c8811f (feature) Line four commit
* 1d4235c Line three commit
* 9eb041a Line two commit
* 8fee707 Line one commit
* 36fd579 (origin/master, origin/HEAD) Initial commit
git branch -d branch-name
- deletes branch-name. To be clear: it does not delete any content from repository, it just removes named reference (branch) to commit.
git remote add <name> <link>
: creates a remotegit remote -v
: lists remotesgit push <remotename> --delete <branchname>
git fetch <remote-name>
: synchronize remote repository (name is not needed if only one remote is configured)git pull
- simple as that. Basically this command does the same as (when run on master branch with proper link to remote is established) :git fetch
git merge origin/master
: By having two steps we can see changes before merge e.g.:git diff master origin/master
git push -u <remote-name> <branch-name>
: pushes to remote a branch (-u
options makes a connection to remote branch used when pushing/fetching. When used it's no longer needed to configure remote branch with--set-upstream
)
TIP: ..git\config - contains branch definition that specifies which remote is associated with our branch when we do push & fetch
TIP: remote branch cannot be checked out! To "checkout" remote branch (create a branch with a starting point from remote) use:
git checkout -b local-branch-name origin/remote-branch-name
git branch --set-upstream-to <remote-branch>
- make a connection between current branch and remote branch. Any future git pull command (with the current local branch checked-out), will attempt to bring in commits from the into the current local branch, e.g.git branch --set-upstream-to origin/master
git stash
: take changes on current branch asidegit stash save "message"
- stash with a messagegit stash list
: lists all stashes
To include untracked files, use --include-untracked
.
git stash show -p <stashid>
-
with apply (apply leaves stash on the list)
-
git stash apply
: take latest stash and apply changes to working directory -
git stash apply <stash-id>
: applies particular stash -
with pop
-
git stash pop
: takes latest stash, applies it and drops it -
git stash pop <stash-id>
: the same for above for particular stash -
git stash branch branchname
- unstash to a branch
git stash drop <stashid>
git stash clear
git checkout <treeish> -- <filename>
: gets file from repository into indexgit reset HEAD filename
: replace staged file with repository content, and keep file changes in working directory. To rephrase: move all changes to working directory.git reset - --soft <treeish>
: does not touch index / working directory and only moves HEAD. Useful when merging multiple commits (provided commits were are in sequence)git revert <sha#>
: reverts changes made in commit by applying another commit
Reset flavours:
--soft
: moves HEAD & does not change staging index or working directory--mixed
(default): moves HEAD & changes staging index to match repository--hard
: moves HEAD & changes staging index and working directory to match repository
git cherry-pick hash
- gets changes made in particular commit and applies them to current branchgit rm <filename>
- remove file from repositorygit rm --cached filename
: ignore already tracked file (removes from repo but leaves in working directory for ignoring)git mv <oldname> <newname>
: renamve / move existing filegit clean -f
- removes all untracked files (usegit clean -n
for test run).gitkeep
: put this dummy file in empty directory that needs to be commited (git by default ignores empty directories)git merge kdiff3
: use kdiff3 http://www.blog.project13.pl/index.php/coding/1192/setup-git-on-windows-to-use-kdiff3-as-its-mergetool/git tag
- lists tags in repogit show-ref <branchname>
- quick way to see commits associated with branches- Rebase vs Merge - it turns out that rebase deletes merge commits (mind-boggling)! It's described here: https://www.derekgourlay.com/blog/git-when-to-merge-vs-when-to-rebase/ .
The Golden Rule of Rebasing: never use it on public branches
Rules of thumb:
- When pulling changes from origin/develop onto your local develop use rebase.
- When finishing a feature branch merge the changes back to develop.
Common usages of rebase:
- cleaning up local history
- incorporating upstream changes into a feature
- integrating an approved feature: by performing a rebase before the merge, you’re assured that the merge will be fast-forwarded, resulting in a perfectly linear history. This also gives you the chance to squash any follow-up commits added during a pull request.
When not to use rebase:
- after pushing / PR. As soon as you make the pull request, other developers will be looking at your commits, which means that it’s a public branch. Re-writing its history will make it impossible for Git and your teammates to track any follow-up commits added to the feature. Any changes from other developers need to be incorporated with git merge instead of git rebase.
git reflog
- gives of log where HEAD has pointed. Find the commit you wish to restore
-
https://www.atlassian.com/git/tutorials/merging-vs-rebasing/workflow-walkthrough - Merging vs. Rebasing
-
https://www.derekgourlay.com/blog/git-when-to-merge-vs-when-to-rebase/ - Git - When to Merge vs. When to Rebase
-
http://blog.thoughtram.io/git/2014/11/18/the-anatomy-of-a-git-commit.html - The anatomy of a Git commit
-
http://stackoverflow.com/questions/2530060/can-you-explain-what-git-reset-does-in-plain-english - how git reset works
-
https://help.github.com/articles/set-up-git : Password caching
-
https://help.github.com/articles/generating-ssh-keys#platform-windows : Generating SSH Keys
-
What is 'recursive stragegy'
-
What is 'fast-forward'