untracked - not tracked ( not in last snapshot ) unmodified - not changed modified - changed but not committed staged - marked for next commit committed - added to DB
index - staging area
sudo dnf install git-all
sudo apt install git-all
MacOS Install: install Xcode Command Line Tools - run git from cli for the first time
or directly download binaries
git --version
[path]//etc/gitconfig
~/.gitconfig or ~/.config/git/config
.git/config
git config --list # check settings
git config --list --show-origin # view all settings and where they are from
--global # set for all projects
git config --global user.name "John Doe"
git config --global user.email johndoe@example.com
git config --global core.editor emacs
git config --global core.editor "'C:/Program Files/Notepad++/notepad++.exe' -multiInst -notabbar -nosession -noPlugin"
git config --global init.defaultBranch main # change default branch name instead of master
git config user.name
git config core.editor
git config --show-origin user.name
git help xxxxx
git xxxx --help
git help config
cd /home/user/my_project
git init
git add *.c
git add LICENSE # version at time you ran this command
git commit -m 'Initial project version'
git clone https://github.com/libgit2/libgit2
git clone https://github.com/libgit2/libgit2 mylibgit
git status # check status
clean - tracked files are unmodified, no untracked files
git add xxxx
# version at time you ran this command, changing again will result in stated/unstaged status
# begin tracking, stage, mark merge-conflicted files as resolved
git status -s # short status
M modified, not staged ( note the leading space )
M modified, staged
MM modified, staged, modified
A new, staged
?? untracked
left char - staging area status right char - working tree status
.gitignore
*.[oa]
*~
/!doc.txt # negate, do track this one
*.txt # glob
/*.txt # leading slash for non recursive
build/ # slash to match dir
a/**/z # match nested dirs, multiple levels
doc/*.txt # not recursive
doc/**/*.pdf # recursive
- multiple .gitignore files can be placed in sub dirs
git diff # compare working dir to staged
git diff --staged # compare staged to last commit
git diff --cached # compare staged to last commit
git difftool --tool-help
git difftool --tool=araxis
git difftool --tool=kompare
git commit # commit, open editor with output of 'git status' commented out, comments stripped after saving
git commit -v # same but with 'git diff'
git commit -m "my update 1 - some changes" # specify commit message
git commit -a -m 'Add new benchmarks' # add all tracked files and commit
git rm test1.java # remove from staging and working dir ( removes from git )
git rm -f test1.java # force if it was already added to staging
git rm --cached output.log # remove from staging ( and from git ) but keep in working dir
# good for accidentally included files that should be ignored
git rm log/\*.log # !!! escape * so we can use git expansion and not shell expansion
Rename like this:
git mv README.md README
Or this:
mv README.md README
git rm README.md
git add README
git will figure out what was renamed.
git log # show commit history
git log -p -2 # show diff / patch output, limit to 2 entries
git log --stat # short stats for each commit
git log --pretty=oneline # one line output
git log --pretty=format:"%h - %an, %ar : %s"
git log --pretty=format:"%H - %an, %cd : %s"
Specifier Description of 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
git log --pretty=format:"%h %s" --graph # branch and merge history
Option Description -p Show the patch introduced with each commit. –stat Show statistics for files modified in each commit. –shortstat Display only the changed/insertions/deletions line from the –stat command. –name-only Show the list of files modified after the commit information. –name-status Show the list of files affected with added/modified/deleted information as well. –abbrev-commit Show only the first few characters of the SHA-1 checksum instead of all 40. –relative-date Display the date in a relative format (for example, “2 weeks ago”) instead of using the full date format. –graph Display an ASCII graph of the branch and merge history beside the log output. –pretty Show commits in an alternate format. Option values include oneline, short, full, fuller, and format (where you specify your own format). –oneline Shorthand for –pretty=oneline –abbrev-commit used together.
git log --since=2.weeks
git log --since=2024-01-01
git log --pretty=oneline --since=2024-01-01
git log -S function_name # Git’s “pickaxe” option - commits that changed occurrences of string
git log --_includes/common_header1.md # commits that changed this file
git log --pretty=oneline -- _includes/common_header1.md # same but one line
–all-match # and instead of or
-
–no-merges # don’t show merge commits
git add . # add forgotton files / missing changes
git commit --amend # ammend to commit ( completly replaces that commit )
Use amend before pushing. Using amend and then force pushing can cause issues for others. ( ? probably fine in a forked setup ? )
git reset HEAD CONTRIBUTING.md # unstage a file
git restore --staged CONTRIBUTING.md # unstage a file (new command in 2.23.0 )
git checkout -- CONTRIBUTING.md # replace file in working dir with last staged or committed version
git restore CONTRIBUTING.md # replace file in working dir with last staged or committed version
Remotes
git remote # show remote servers ( short names )
git remote -v # also show URLs
origin - default name for server that repo was cloned from local master is setup to track orgin master ( or default branch ) when cloning remote repo
git remote add pb https://github.com/paulboone/ticgit # shortname, URL
git fetch # get all info, you can then use other branches that you didn't have
git fetch pb # get all info from this remote
git fetch origin # get all info from this remote
git pull # fetch and merge into current branch ( usually from origin master )
git config --global pull.rebase "false"
* default behavior of Git (fast-forward if possible, else create a merge commit)
* 2.27 might give warnings about pull.rebase not being set on git pull
git push origin master
git push
git remote show origin # inspect remote, shows which branches are tracked and how they map out
git remote rename pb paul # rename a remote
git remote remove paul # remove a remote
git remote rm paul # remove a remote
Tags
git tag # list tags
git tag -l "v1.8.5*" # list matching tags
lightweight tags - just a pointer to a commit annotated tags - full objects with a bunch of info ( recommended )
git tag -a v1.4 -m "my version 1.4" # create annoteted tag, -m to specify message
git show v1.4 # show it
git tag v1.4-lw # create lightweight tag
git show v1.4-lw # show it
git tag -a v1.2 9fceb02 # tag existing commit
git push origin v1.5 # push a tag to remote
git push origin --tags # push all tags
git push origin --follow-tags # only annoteted tags
git tag -d v1.4-lw # delete local tag
git push origin :refs/tags/v1.4-lw # delete remote tag ( overwrite with null value )
git push origin --delete v1.4-lw # delete remote tag
git checkout v2.0.0 # checkout a tag ( but results in detached HEAD )
git checkout -b version2 v2.0.0 # create a branch based on a tag
Aliases:
git config --global alias.co checkout
git config --global alias.br branch
git config --global alias.ci commit
git config --global alias.st status
git config --global alias.unstage 'reset HEAD --'
git config --global alias.last 'log -1 HEAD'
git config --global alias.visual '!gitk' # ! for external command
Brancing
git branch # list branches
git branch -v # list branches with last commit
git branch --merged # show branches that are already merged into current branch
git branch --no-merged # not merged yet
git branch --no-merged master # what isn't merged into master
git branch testing # create new branch pointing to current commit, DOESN'T switch to it
git checkout testing # switch to existing branch
git checkout master # switch back
git checkout -b test2 # create and switch to new branch
git switch testing # switch to existing branch ( v2.23 and up )
git switch -c test2 # create and switch to branch
git switch - # switch to previous checked out branch
HEAD - pointer to current branch
git log --oneline --decorate # show where branch pointers are pointing
git log --oneline --decorate --graph --all # show graph of all branches
git log testing # show history for this branch
git log --all # show history for all branches
git checkout master
git merge hotfix # hotfix merged into master, both will point to same commit
git branch -d hotfix # remove branch
git branch -D hotfix # remove branch that hasn't been merged
merging - fast forward if there is a direct chain, just moves pointer forward
- recursive strategy - three way merge - 1 common ansestor and 2 branch tips, results in new commit
( merge commit - has more than one parent )
merge conflict:
git status # show which files are unmerged ( Unmerged paths: )
Manually edit each section in each file that looks like this:
<<<<<<< HEAD:index.html
=======
>>>>>>> iss53:index.html
git add index.html # add each file that was manually edited
git mergetool # fire up a gui tool, can probably edit and add
git commit # finish the merge
Cancel a merge in progress:
git merge --abort
Always commit or stash before merging, aborting a merge could result in lossing uncommitted files.
Fast-forward merge - just move pointer forward Recursive merge - 3 way merge: 1 common ancestor, 2 branch tips Octopus merge - multiple branches all merged at once
git branch --move bad-branch-name corrected-branch-name # rename branch locally
git push --set-upstream origin corrected-branch-name # push renamed branch to remote
git push origin --delete bad-branch-name # remove old branch name from remote
git branch --all # show all branches
git branch --move master main # rename master to main, can break things
git push --set-upstream origin main
git push origin --delete master
Branching Workflows
Long-Running Branches
ex: master - stable / prod dev - unstable /dev
topic branches short lived branches
ex: topic/silly_bug_fix
- topic branches can be merged into dev and dev cna be merged into master
commit history is still branched after removing branch:
$git log --oneline --decorate --graph --all
* 9e54cb2 (HEAD -> master) Merge branch 'topic/abc123'
|\
| * 59cfb94 (topic/abc123) update
* | 595b1af update
|/
* 25e7897 update
* a3a00e1 update
* a7d16a5 update
$git branch -d topic/abc123
Deleted branch topic/abc123 (was 59cfb94).
$git log --oneline --decorate --graph --all
* 9e54cb2 (HEAD -> master) Merge branch 'topic/abc123'
|\
| * 59cfb94 update
* | 595b1af update
|/
* 25e7897 update
* a3a00e1 update
* a7d16a5 update
$
Git show remote references:
git ls-remote
git remote show
</code></pre>
Remote-tracking branches - RO pointers to remote branches so you can track them
/.
git push origin serverfix # push a branch to remote
git push origin serverfix:awesomebranch # use different branch name on remote
git config --global credential.helper cache # temp 15 min cache
git config --global credential.helper 'store --file ~/.my-credentials' # clear text in file
git merge origin/serverfix # merge remot branch with current local
git checkout -b serverfix origin/serverfix # create local branch from remote branch and tracks it
git checkout --track origin/serverfix # same
git checkout -b sf origin/serverfix # use different local name
git branch -u origin/serverfix # track specific remote branch on current local ( or change the tracked branch )
git merge @{u} # shortcut for remote branch
git branch -vv # show what each branch is tracking ( since last fetch )
git fetch --all; git branch -vv
git pull # fetch and merge current local branch with current remote
tracking branch tracks an upstream branch
git push origin --delete serverfix # delete remote branch
## Rebasing
git checkout experiment
git rebase master # pull in all changes from master and apply them before any changes in experiment
git checkout master # back to master
git merge experiment # can now do a fast forward merge
rebase:
* save all changes that were made to current branch ( diffs between HEAD and common ancestor )
* move HEAD back to common ancestor commit
* add all changes from other branch
* add changes for current branch back in
* afterwards, can merge with fast forward for a linear history
make sure your commits apply cleanly on a remote branch ( good if someone else maintains it )
Example:
* Take client branch changes since it diverged from server branch
* Replay those on top of the current master branch
* The point the client branch to point to the tip of that
* Then merge ( fast forward ) master to this
git rebase --onto master server client
git checkout master
git merge client
* Rebase server onto master without having to check it out
* Then merge ( fast forward ) that too
git rebase master server
git checkout master
git merge server
Remove the topic branches:
git branch -d client
git branch -d server
### Cancel Rebase
git rebase --abort # cancel rebase
git rebase --quit # if cancelling didn't work
### The Perils of Rebasing
"Do not rebase commits that exist outside your repository and that people may have based work on."
Scenario:
* Someone else pulls your branch before you rebase
* You rebase and force push
* They push it back up after you rebase
* It will include your old changes and your rebased version of those changes ( duplicate commits ).
* Keeps getting more messed up from there.
I've you have someone elses rebased work, you can rebase again and git should figure out which commits are duplicates and which need to be added ( rebase on top of force pushed rebase ).
git fetch
git rebase teamone/master
OR
git pull --rebase
Rebase vs Merge
Rebase - cleaner, not a "first draft", more coherent story
Merge - preserve history, how it actually happened
## Git Revert
git revert 25e7897d1ce4ca817555d71ac158d8e7112bded5 # revert a commit ( just changes from this commit ), creates new commit for this
git revert HEAD # revert last commit in current branch
git reset 25e7897d1ce4ca817555d71ac158d8e7112bded5 # revert to this point and any other commit after it ( HEAD goes back to this commit )
## Squashing
Squashing with merge:
git merge --squash
Squash local commits:
git rebase -i
Squash to whatever is in origin/master:
git rebase -i origin/master
git push -f
If there are conflicts:
git add .
git rebase --continue
## Cherry Pick
git cherry-pick e43a6 # pull a specific commit from any other branch into your HEAD branch
git cherry-pick af02e0b --no-commit # only add to current copy
## Git Stash
"Stash the changes in a dirty working directory away"
git stash # stash uncommitted changes ( staged and unstaged, not untracked )
git stash -u # include untracked files
git stash list # Show stashes
git stash show # show operations performed on the stash
git stash save "message" # message for this stash (deprecated)
git stash push "message" # message for this stash
git pop # remove changes from stash, restore to working dir and index
git apply # keep in stash but also restore to working dir and index
git stash branch newbranch # create new branch based on stash and the commit it was based on, latest stash
git stash branch newbranch stash@{0} # same but specify the stash
git stash drop stash@{1} # remove a stash
git stash clear # remove all stashes
## Git Server
bare repository — git repo with no working directory
Protocols: Local, HTTP, Secure Shell (SSH) and Git
### local
local - local file system ( or NAS )
git clone /srv/git/project.git # tries to use hard links and file copying
git clone file:///srv/git/project.git # transfers using network
git remote add local_proj /srv/git/project.git # add local repo to existing project as a remote
### HTTP
* need web server, and some other steps
Smart HTTP # pre 1.6.6
username/password authentication
anonymous or with encryption and auth
Dumb HTTP # 1.6.6 and later
### SSH
* requires key setup ( probably )
* requires ssh access to host ( might not want this for public stuff but fine on home or corporate networks )
* comes with encryption and auth
Clone over SSH:
git clone ssh://[user@]server/project.git
git clone [user@]server:project.git
### Git Protocol
* no security
* no encryption
* no auth
* port 9418
* git daemon can serve this
* usually no push access but can be enabled
* supposed to be fast, same transfer mechanism as SSH but no auth or encryption
git-daemon-export-ok - file must exist in repo for daemon to serve the repo
git clone git://example.com/project.git