History
-
In 2002 Linux kernel project began using a proprietary DVCS called BitKeeper.
-
In 2005 the tool was not free any more as the commercial company of BitKeeper and the Linux kernel team broke their relationship. Then Git was developed by the Linux development community.
-
Goals of Git:
- Speed
- Simple design
- Strong support for non-linear development (thousands of parallel branches)
- Fully distributed
- Able to handle large projects like the Linux kernel efficiently (speed and data size)
What is Git
-
Distinction between Git and nearly all other VCSs.
-
With Git, every time you commit, or save the state of your project, Git basically takes a picture of what all your files look like at that moment and stores a reference to that snapshot.
-
To be efficient, if files have not changed, Git doesn’t store the file again, just a link to the previous identical file it has already stored. Git thinks about its data more like a stream of snapshots.
-
-
All the git histories are stored in the local database -- fast and no need to be online all the time
-
Everything in Git is checksummed before it is stored and is then referred to by that checksum. It uses a SHA-1 hash -- a 40-character string composed of hexadecimal characters (0–9 and a–f) and calculated based on the contents of a file or directory structure in Git.
-
Only adds data to the Git database
-
File states in Git -- modified, staged, committed
-
- Modified means that you have changed the file but have not committed it to your database yet.
- Staged means that you have marked a modified file in its current version to go into your next commit snapshot.
- Committed means that the data is safely stored in your local database.
First-time Git setup
-
config files:
[path]/etc/gitconfig
-- every user~/.gitconfig
or~/.config/git/config
-- specific userconfig
file in the Git directory (that is,.git/config
) -- specific repository
-
git config
is a command used in Git to set configuration options for your Git installation. These configurations can be set at three levels:- System level: Applies to every user on the system and all their repositories.
- Global level: Applies to the user level, i.e., for all repositories of the current user.
- Local level: Applies only to a specific repository.
-
How to use
git config
:-
List all settings: You can list all Git configuration settings with:
git config --list --show-origin
git config user.name
git config --list -
List settings for a specific level: To list settings for a specific level, use
--global
,--system
, or--local
:git config --global --list
-
Setting Configurations
- Set a user name and email: This is commonly used to identify the author of commits.
git config --global user.name "Your Name"
git config --global user.email "your_email@example.com" -
Set an editor: To set a default text editor for Git (e.g., Vim, Nano, or Notepad++).
git config --global core.editor "vim"
git config --global core.editor emacs -
Get a specific configuration value: If you want to check the value of a specific configuration, you can use:
git config user.name
-
Set color UI: To enable colored output in Git commands.
git config --global color.ui auto
-
Set alias: You can create shortcuts for commonly used Git commands.
git config --global alias.st status
Afterwards, you can use
git st
instead ofgit status
.- Set default branch name: For new repositories, set the default name of the initial branch (e.g.,
main
instead ofmaster
).git config --global init.defaultBranch main
-
-
Global Configuration File: This is typically located in your user home directory, under
.gitconfig
. -
Local Configuration File: Found in the
.git/config
file in a Git repository. -
Settings at a more specific level (local) override settings at a more general level (global/system)
-
Getting help
$ git help <verb>
$ git <verb> --help
$ man git-<verb>
$ git help config
- More concise version of
git help
is-h
, eg.git add -h
Git Basics
-
git init
-
git add *.c
orgit add LICENSE
-
git commit -m xxxx
-
git clone https://
orgit clone git://
orgit clone user@server:path/to/repo.git
or
git clone url diretory
-
file state changes
- Add the file:
untracked
-->staged
- Remove the file:
unmodified
-->untracked
- Edit the file:
unmodified
-->modified
- Stage the file:
modified
-->staged
- Commit:
staged
-->unmodified
git status
orgit status -s
orgit status --short
- Add the file:
-
ignore files:
.gitignore
- Blank lines or lines starting with # are ignored.
- Standard glob patterns work, and will be applied recursively throughout the entire working tree.
- You can start patterns with a forward slash (/) to avoid recursivity.
- You can end patterns with a forward slash (/) to specify a directory.
- You can negate a pattern by starting it with an exclamation point (!).
# ignore all .a files
*.a
# but do track lib.a, even though you're ignoring .a files above
!lib.a
# only ignore the TODO file in the current directory, not subdir/TODO
/TODO
# ignore all files in any directory named build
build/
# ignore doc/notes.txt, but not doc/server/arch.txt
doc/*.txt
# ignore all .pdf files in the doc/ directory and any of its subdirectories
doc/**/*.pdf -
git diff
compares what is in your working directory with what is in your staging area -
git diff --staged
orgit diff --cached
can see what you’ve staged that will go into your next commit -
git commit
/git commit -m xxxx
-
If don't want to use
git add .
before committing them, can usegit commit -a -m xxx
-
Removing files:
git rm a.txt
stages the removal of the file for the next commit.git rm a.txt --cached
removes a file from the repository but keep it in your working directory.gir rm -r [directory]
removes a directory- deletion with wild cards: use a backslash () in front of it
git rm -f
is used when the file being added but has not been committedgit rm \*.txt
==git rm '*.txt'
-
Moving files:
git mv file-a file-b
which is equivalent to
mv file-a file-b
git rm file-a
git add file-b -
Viewing the commit history
git log
git log -p -2
orgit log --patch -2
viewing the differences in the last two commitsgit log --stat
outputs a summary at the end- formatting log output:
-
git log --pretty=oneline
orgit log --oneline
-
git log --pretty=format:"%h - %an, %ar : %s"
-
Useful specifiers for
git log --pretty=format
specifier Output %H Commit hash %h Abbreviated commit hash %T Tree hash %t Abbreviated tree hash %P Parent hashes %p Abbreviated parent hashes %an Author name %ae Author email %ad Author date (format respects the --date=option) %ar Author date, relative %cn Committer name %ce Committer email %cd Committer date %cr Committer date, relative %s Subject -
The
author
is the person who originally wrote the work, whereas thecommitter
is the person who last applied the work. -
git log --pretty=format:"%h %s" --graph
-
Common options to
git log
:--pretty=oneline/short/full/fuller/format
--relative-date
eg. outputs 'two weeks ago'--stat
/--short-stat
/--name-only
/--name-status
/--abbrev-commit
git log --since=2.weeks
/git log --since=2008-01-15
--author
filters authors,grep
can be used to filter certain commits with keywordsgit log -S[string]
- To search for changes involving
function_name
:git log -Sfunction_name
- to show diffs
git log -p -Sfunction_name
-i
case insensitive- limit the search to a specific file
git log -Sfunction_name -- [filepath]
-n
show only the last n commits--since
,--after
--until
,--before
--author
--comitter
--grep
only shows commits with a commit message containing the string-S
only show commits adding or removing code matching the string
- to show diffs
-
-
Undoing things
git commit --amend
- unstaging a staged file
git reset HEAD <file>...
orgit restore --staged <file>…
- unmodifying a modified file
git checkout -- <file>...
orgit restore <file>
-
Working with remotes
git remote
/git remote -v
- for
git remote -v
, it would list all the remotes, which means we can pull/push to all the remotes - Adding remote repositories:
git remote add <shortname> <url>
git remote add pb <url>
git fetch pb
git fetch <remote>
git pull
git config --global pull.rebase "false"
git push <remote> <branch>
- inspecting a remote
git remote show origin
- remame a remote
git remote rename pb paul
- remove a remote
gir remote remove paul
-
Tagging
- list tags
git tag
, lists the tags in alphabetical order; the order in which they are displayed has no real importance. git tag -l "v1.8.5*"
listing tag wildcards requires -l or --list option- creating tags -- lightweight or annotated
- annotated:
git tag -a v1.4 -m "my version 1.4"
andgit show v1.4
- lightweight:
git tag v1.4-lw
andgit show v1.4-lw
- add a tag for a past commit:
git tag -a v1.2 9fceb02
andgit show v1.2
git push
command doesn’t transfer tags to remote servers, so we need to share tages to remote servers,git push origin <tagname>
- if there are many tags that need to be pushed
git push origin --tags
- annotated:
- deleting local tags
git tag -d v1.4-lw
- deleting remote tages
git push origin --delete <tagname>
- In “detached HEAD” state, if you make changes and then create a commit, the tag will stay the same, but your new commit won’t belong to any branch and will be unreachable, except by the exact commit hash.
- To fix a bug in a certain version(tag), we need to use branch
git checkout -b version2 v2.0.0
- list tags
-
git alias
git config --global alias.gcl 'clone'
, then we can usegit gcl xxx
-
To make
git clone
==gcl
, you have to set it in the shell:alias gcl='git clone'
Git Branching
-
A branch in Git is simply a lightweight movable pointer to one of these commits
-
create a new branch
git branch xxxx
-
a special pointer called
HEAD
lets git know which branch you are on -
to see which branch you are on
git log --oneline --decorate
-
switching branches
git checkout testing
moves HEAD to point to the testing branch -
create a new branch and want to switch to that new branch at the same time
git checkout -b <newbranchname>
-
from git version 2.23,
git switch existing-branch
==git checkout existing-branch
-
basic merging
git checkout [target-branch]
git merge [source-branch]
git add [conflicted-file]
git commit
git push origin [target-branch] -
git mergetool
fires up an appropriate visual merge tool and walks you through the conflicts -
list current branches
git branch
,*
character that prefixes the master branch: it indicates the branch that you currently have checked out -
see the last commit on each branch
git branch -v
-
--merged
and--no-merged options
options -
delete a branch
git branch -d
, to force it,git branch -D
-
change branch name
git branch --move old-name new-name
git push --set-upstream origin new-name
git push origin --delete old-name -
change the master branch name from
master
tomain
git branch --move master main
git push --set-upstream origin main
git push origin --delete master -
branching workflow -- long running
- a typical workflow: the
main
branch only has code that has been or will be released, and have another parallel branch nameddevelop
ornext
that they work from or use to test stability, and when it gets to a stable state, it can be merged intomain
- it can be done for several levels of stability
- a typical workflow: the
-
banching workflow -- short lived
- open a few topic branches to implement any functions or fix a bug in them, then merge them into the
main
branch - it can be done with several levels as well
- open a few topic branches to implement any functions or fix a bug in them, then merge them into the
-
remote branches
git ls-remote <remote>
orgit remote show <remote>
- remote-tracking branches are references to the state of remote branches
- Remote-tracking branch names take the form
<remote>/<branch>
. - when doing
git clone
, in your local repository will have a pointer that points to the remote main branch, which isorigin/main
, and also have a pointer points to the local main branch, which ismain
, after you made some changes and commits on themain
branch, your localmain
pointer moves, while the remoteorigin/main
pointer still remains in the old location. - “origin” is the default name for a remote when you run git clone. If you run
git clone -o booyah
instead, then you will have "booyah/main" as your default remote branch.
-
adding multiple remote servers
git remote add teamone xxxxx
git fetch teamone
git fetch origin -
share a local branch to remotes
git push <remote> <branch>
, then others can fetch it and see the new branch while runninggit fetch orgin
/git fetch teamone
git push origin a-new-local-branch-name
git push teamone a-new-local-branch-name -
tracking branches
-
When Creating a New Local Branch:
git checkout -b [local-branch] [remote-name]/[remote-branch]
git switch -c [local-branch] [remote-name]/[remote-branch]
-
Setting an Existing Local Branch to Track a Remote Branch:
git branch -u [remote-name]/[remote-branch] [local-branch]
- if you are currently checked out in the local branch:
git branch -u [remote-name]/[remote-branch]
-
benefits:
-
Simplified Push and Pull: When you have a tracking relationship set up, you can use git push and git pull without specifying the remote and branch name.
-
Status Information: Running git status on a tracking branch shows how many commits the local branch is ahead or behind the remote branch.
-
Automatic Remote Branch Updates: Running git fetch automatically updates the status of your remote-tracking branches.
-
-
see the tracking relationships:
git branch -vv
-- it shows info from the local database -
to hav up-to-date info, fetch from all your remotes right before running this
git fetch --all; git branch -vv
-
-
git pull
-
delete remote branches
git push origin --delete serverfix
-
git rebase
- if using merging to merge
experient
tomain
:git merge
- if using rebase:
git checkout experiment
git rebase main
git checkout main
git merge experiment - if using merging to merge
-
git rebase --onto master server client
git checkout master
git merge clientgit rebase master server // equivalent to git checkout server and git rebase master
git checkout master
git merge server
git branch -d server
git branch -d client -
Do not rebase commits that exist outside your repository and that people may have based work on.
Git on the Server
-
Git can use four distinct protocols to transfer data: Local, HTTP, Secure Shell (SSH) and Git.
-
Putting the Bare Repository on a Server:
scp -r my_project.git user@git.example.com:/srv/git
ssh user@git.example.com
cd /srv/git/my_project.git
git init --bare --shared -
Setting up the Server:
sudo adduser git
su git
cd
mkdir .ssh && chmod 700 .ssh
touch .ssh/authorized_keys && chmod 600 .ssh/authorized_keys
cd /srv/git
mkdir project.git
cd project.git
git init --bare
-
on a client
cd myproject
git init
git add .
git commit -m 'Initial commit'
git remote add origin git@gitserver:/srv/git/project.git
git push origin master -
then others can do:
git clone git@gitserver:/srv/git/project.git
-
Git Daemon / Smart HTTP / GitWeb / GitLab
Miscellaneous
-
git reset --hard 1a410efbd13591db07496601ebc7a059dd55cfe9
-
git reflog
-
git log -g
-
$ git fsck --full
Checking object directories: 100% (256/256), done.
Checking objects: 100% (18/18), done.
dangling blob d670460b4b4aece5915caf5c68d12f560a9fe3e4
dangling commit ab1afef80fac8e34258ff41fc1b867c702daa24b
dangling tree aea790b9a58f6cf6f2804eeac9f0abbe9631e4c9
dangling blob 7108f7ecb345ee9d0084193f147cdad4d2998293 -
$ git gc
Counting objects: 17, done.
Delta compression using up to 8 threads.
Compressing objects: 100% (13/13), done.
Writing objects: 100% (17/17), done.
Total 17 (delta 1), reused 10 (delta 0) -
$ git count-objects -v
count: 11
size: 4904
in-pack: 15
packs: 1
size-pack: 8
prune-packable: 0
garbage: 0
size-garbage: 0