Git - kamialie/knowledge_corner GitHub Wiki
- Get started
- Git basics
- Branches
- Git tools
- Patch workflow
- Plumbing
- Tips and tricks
- Useful commands
- References
Popular Distributed Version Control Systems (DVCS) - Git, Mercurial, Bazaar, Darcs.
In comparison to other VCSs, which use delta-based version control (have a base file and each version is a difference made to that file), git makes a snapshot of all files on every version. If file has not changed, stores a reference (a link to previous identical file it has already stored.
Git uses SHA-1 hash mechanism for checksumming for all kind of operations as file change detection, storing, etc.
Three main states that a file can have:
- modified - file modified but not committed
- staged - marked modified file to go into next commit snapshot
- committed - data is stored in local database
Configuration variables that control all aspects of Git can be stored in three different places:
-
/etc/gitconfigfile - values are applied to every user on the system and all their repositories; pass --system option to git config to operate on values from this file specifically -
~/.gitconfigor~/.config/git/configfile - values related to a specific user; pass --global option to git config to operate on this file; affects all repositories of the user -
.git/config- values applied to specific repository; pass --local to set values to config file located in the.gitrepo of the current repository
Set identity(this information is added to every commit):
git config user.name <name>git config user.email <email>
Git uses specified editor when user needs to type in a message. If not configured, system's default is used:
git config core.editor vim
Working with settings (if no config level parameter is specified, --local is assumed):
-
git config <setting>- check specific setting -
git config --show-origin <setting>- show setting as well as where Git took it from -
git config --list- view all settings -
git config --edit- edit values in configured editor -
git config --unset <setting>- remove a setting
Turn on autocompletion in bash:
- move
git-completion.bashfile to home directory - source it to bashrc with the following line -
. ~/git-completion.bash
Documentation (also includes list of available options)
Commands to get man pages:
git help <verb>git <verb> --helpman git-<verb>-
git <verb> -h- concise help output, refresher
- Blob - represents the metadata for individual file
- Tree - lists the contents of the directory and specifies which file names are stored as which blobs
- Commit - contains the pointer to the tree and all commit metadata; if its not a root commit, it also contains pointers to parent(s)
Thus when git stages files, it computes checksums for each file and stores that version of the file in the Git repository (blob). When git performs commit command, it checksums each subdirectory of the project and stores them as a tree object. Commit objects contains commit metadata and pointers to the trees.
git init - creates subdirectory (.git), repository skeleton
- --bare - creates a bare repository without working directory, thus, can't be used for development, but rather used as storage facility; has same contents as .git subdirectory
git clone <repo_path> [directory] - copy existing repository to local machine;
optional directory argument specifies where repository will be created
-
[--origin], [-o] <remote>- give other name to refer to remote, other than the default nameorigin
git status - show status of all files in the current repository, can be tracked (unmodified | modified | stages) or untracked.
-
[--short], [-s]- short version; 1 column is staged area, 2 column - working tree; corresponding signs are:- ? - new files
- A - added to staged area
- M - modified files
git add - add file(s) to the staging (index) (new | modified | resolve conflicts)
.gitignore - add files or patterns to ignore, examples;
it is possible to have multiple gitignores in subdirectories, which will only
apply to files inside that directory. .git/info/exclude file can be used to
specify which files to ignore in current repository, without sharing it with
remote.
- start pattern with slash (/) to avoid recursivity
-
/TODO- only ignore TODO file in the current directory, not subdir/TODO
-
- end pattern with slash (/) to specify a directory
-
build/- ignore all files in any directory named build
-
- negate pattern by starting it with an exclamation point (!)
-
*.a- all files in a repository, including in nested directories -
!lib.a- do track lib.a, even though you ignore *.a files
-
- use 2 asterisks (**) to match nested directories
-
doc/**/*.pdf- ignore all pdf files in the doc/ directory and all its subdirectories
-
-
*matches anything,?matches any single character (both match all except/),[]are used to specify ranges ([a-z])
git diff
Shows changes that were introduced between two references; without arguments
shows uncommitted (unstaged) changes. Use git diff HEAD to show both
unstaged and staged changes. When second argument is omitted, HEAD is assumed.
# Changes in current working directory (not staged)
$ git diff
# Changes between staged changes and last commit
$ git diff --cached
# Changes between all changes (staged and unstaged) and last commit
$ git diff HEAD
# Changes between specified references; add optional file path(s) to limit
# output to specific file(s)
$ git diff <ref1> <ref2> [file_path]
$ git diff HEAD~2 HEAD example.txt
# Changes in main since feature was created from it
$ git diff feature...main-
--stagedor--cached- shows changes only in staging area (difference between last commit and staged changes) -
-w- ignore white-space changes
Output of git diff:
- Git applies labels to file versions, a and b
diff --git a/example.txt b/example.txt` - Same files also have corresponding hashes, see specific file with
git show <hash>index 3709d20c7a8..f54d21c504b 100644` - Git shows file markers for corresponding file versions,
/dev/nullis file was deleted or just created--- a/.bazelrc +++ b/.bazelrc - Chunk headers summarize what is displayed below; for file a 6 lines are
displayed starting from line 3, for file b 7 lines are displayed starting
from line 3.
@@ -3,6 +3,7 @@
git difftool - allows for graphical view in configured editor, run git difftool --tool-help to get more details.
git commit - commit staged changes (create a snapshot); with no arguments launches the chosen (--global core.editor) editor - lines starting with # will be ignored.
-
-v- in addition to default call adds the output of diff command -
-m <message>- alternative, commit message -
-a- skip the staging area - automatically add all files that are already tracked (does not include new, untracked files)
git rm <file> - remove file from working directory and stage the removal; add
--cached flag to only remove it from Git tracking, but not from disk.
-
--cached <file>- remove file from staging area, but not from working directory (for example forgot to add to gitignore)-
log/\*.log- can pass files, directories and file-glob patterns, backslash before start in necessary, as git applies its own filename expansion in addition to shell's expansion
-
git mv <file_from> <file_to> - convenience command, applies mv,
removal of old name and staging of new new (will appear as renamed in git
status)
git log - with no arguments lists all commits in chronological order (from most recent); pretty option with one line or format specifiers work particularly well with graph option.
-
--patchor-p- show difference introduced in each commit -
--stat- show changes per file - additions, deletions, etc -
--shortstat- same as above, but obviously short -
--pretty=[oneline | short | full | fuller | format]- outline info in different format than the default; all except format are built-ins, while format lets you create your own (see below)-
git log --pretty=format:"%h - %an, %ar : %s"- example - %H - commit hash
- %h - abbreviated form
- %T - tree hash
- %t - abbreviated form
- %P - parent hashes
- %p - abbreviated form
- %an - author name
- %ae - ... email
- %ad - ... date
- %ar - ... date, relative
- %cn - committer name
- %ce - ... email
- %cd - ... date
- %cr - ... date, relative
- %s - subject
-
-
--graph- nice little ASCII graph -
--name-only- show the names of file modified after each commit info -
--name-status- same as above with added/modified/deleted info as well -
--abbrev-commit- abbreviated form for checksum -
--relative-date- display date in relative format -
--oneline- shorthand for--pretty=oneline--abbrev-commit together
git show <identifier> - show git log -p output on specified commit
through identifier
git shortlog - group commits by user.
Useful combinations:
$ git log --oneline --graph-
-<n>- where n is an integer show lastncommits -
--sinceor--until- specify the date; can accept different formats:- "2.weeks"
- "2009-01-15"
- "2 years 1 day 3 minutes ago"
-
--author- show commits from particular author -
--grep- search for keywords in the commit messages -
-S <string>- Git's "pickaxe" option, takes a string and show only those commits that changed number of occurrences -
-- /path/to/file/or/directory- output commits that introduced a change to those files -
--no-merges- not merge commits
git commit
-
--amend- redo last commit (in case of forgetting to add some files, changing commit message, making additional changes), in other words take the staging area and uses it for the commit (actually takes last commit away, creates new one and pushes it over); f.e.:$ git commit -m "initial commit" $ git add <forgotten_file> $ git commit --amend
git reset HEAD <path/to/file/or/directory> - unstage the specified file or
directory
git checkout -- <path/to/file/or/directory> - unmodify a file, revert it
to last commit
git revert <reference> - creates a revert commit to the specified
reference (both staged and committed); docs
Remote repositories are version of the project that is hosted elsewhere (can be remote server, network, internet, even local machine).
origin is the default name Git gives to the server that you clone from.
upstream is a convention for referencing forked repositories (usually in
open source development).
git remote lists configured remote repositories (on git clone Git automatically adds remote, by default named origin, pointing to original repo).
-
-v- show URLs as well (URL can also be a local absolute or relative path) -
add <remote_name><remote_path>- add a remote -
show <remote_name>- see more info about particular remote -
rename <old_name> <new_name>- rename remote's short name (changes references as well, f.e.<old_name>/masterto<new_name>/master) -
remove <remote_name>or rm<remote_name>- remove remote, all remote-tracking branches and configs are deleted as well
Git fetch pulls down all data from the remote project that you don't have locally. After it you have all references to all branches locally and can merge or inspect at any time. Does not merge data automatically. If current branch is set up to track a remote branch, then git pull automatically does git fetch and then tries to merge the changes.
git fetch <remote> - get the data from the remote server
-
<remote_branch>:<local_branch>- fetch remote branch into local branch (without checking out to that branch)
git push sends local update to remote repository.
# Push changes to remote branch. Doesn't add remote tracking - add -u flag to
# also create a remote tracking. Subsequent push would be able to just use a
# shortcut by running "git push" without specifying a branch, which would
# default to current local branch.
$ git push <remote_name> <branch_name>
# Example above is a shortcut to the command below; use it if local branch has
# a different name than the remote one
$ git push push <remote_name> <local_branch_name>:<remote_branch_name>Tags are used to explicitly mark certain points in history. They can be used as references in all other commands like checkout, cherry-pick, etc.
Types of tags:
- lightweight - just like branch, but doesn't change, in other words it points to
specific commit; to create a lightweight tag don't pass any additional
options -
git tag v1.4-lw - annotated - stored as full object in Git database (checksummed as well), since it contains additional information - tagger name, email, and date. (can also be signed and verified by GNU Privacy Guard, GPG)
git tag <pattern> - list existing tags, optional pattern (enclosed in
double quotes) can be passed as well
-
--listor-l- act like default for entire list of tags; if pattern is supplied flag is mandatory for desired behavior -
-a <tag_name> <commit_checksum>- create annotated tag; optional<commit_checksum>parameter to tag past commits (short or full version of checksum) -
-m <message>- specify tagging message -
-d <tag_name>- remove a local tag
git show <tag_name> - show the tag data alongside commit info.
git push <remote_name>:
-
<tag_name>- push tag to remote server -
--tags- push all tags at once (pushes both types of tags) -
--delete <tag_name>- remove tag from remote server -
:ref/tags/<tag_name>- way to interpret - read the value before colon as null, thus pushing null == deleting tag
Simple as any other aliasing - just replace "long" command with you alias!
git config --global alias.<alias> <command> - if command consists of
multiple arguments, its best to enclose them in single quotes
Good examples:
git config --global alias.co checkoutgit config --global alias.br branchgit config --global alias.ci commitgit config --global alias.st statusgit config --global alias.last 'log -1 HEAD'git config --global alias.lo 'log --oneline'
[redo]
Remotes are for people, whereas branches are for topics.
Summary: creating a branch in Git is just writing small metadata file, which acts like a pointer to commit.
git branch - list all local branches
git branch <name> - create a new branch; actually creates a new pointer to
the commit you are currently on
To keep track where you are currently on Git uses special pointer HEAD - it
shows where you are on in the local repository.
git checkout <tag | commit | branch> - switch to the provided commit, branch
(moves HEAD)
git checkout - - switch to the previous commit, branch
git checkout -b <name> - create and switch to a branch at the same time
git checkout was split to git switch (to work with branches) and git restore (to work with fetching files from other revisions). Original
checkout is still available though. New switch and restore commands.
The setup for merging is usually the following - a branch was created from a main branch to do some additional work. That work was then committed to that branch. Now the work on separate branch needs to be incorporated to the main branch.
Performing merge can lead to 3 cases:
- fast-forward merge - source branch can be reached by following target branch's commit history, meaning source branch was directly ahead of target branch; git simply moves the pointer ahead
- 3 way merge - source branch have diverged from target branch and there are no conflicts, so git creates new snapshot (merge commit), which is created from two tips of branches and their common ancestor
- source branch have diverged from target branch and there are some conflicts,
so git pauses and lets user resolve conflicts (then one can add/commit the
work); list unmerged files by running
git status
git merge - merge referenced revision into current branch
-
--no-ff- force a merge commit where Git would normally do a fast-forward -
-m <message>- provide a merge commit message
git merge - - merge previous branch into current one.
git mergetool - open graphical tool to resolve conflicts, append tool name to use other than default
-
--tool-help- get help, e.g. tool is not configured
Merge conflict markers; content on the current branch is marked as head, and comes first, content on the branch that merge is performed from is displayed second.
<<<<<<< HEAD
one
two
=======
three
four
>>>>>>> main
git branch
-
-v- list branches and their last commits as well -
-vv- include remote branch name, if local branch has a remote tracking set -
--merged- list branches that are already merged into the branch you are currently on (good candidates to be deleted, since the current branch contains their work) -
--no-merged- list branches that contain work that have not been merged into branch you are currently on (trying to delete this branch will result in warning) -
-r- list remote branches (always specified in the<remote-name>/<branch-name>form, not to be confused with local branches) -
-m <current_name> <new_name>- rename branch; skip first argument to rename current branch;-Mif new_name already exists
--merged and --no-merged are relative to current branch if no argument is
passed
git branch -d <name> - delete branch locally, with -D flag to force delete
(in case of unmerged changes).
git ls-remote <remote> or git remote show <remote> - get full list of remote
references or remote branches with more info respectively.
Remote branch's name takes the form <remote>/<branch>, for example
origin/master.
You have cloned a repository (thus your master and origin/master refer to the
same commit), but later on someone has push to server and you have committed
further locally. Run git fetch <remote> to get the latest version of origin to
you local repository.
git checkout -b <branch> <remote>/<branch> - merge remote branch into
current working branch, thus local branch tracks the remote one.
git checkout --track <remote>/<branch> - create and check out to
"tracking branch" - local branch that has direct relationship with remote branch
(git knows where to push, pull, etc).
git checkout <branch> - shortcut for the above, if branch does not exist
locally (and only exists on one remote) Git creates "tracking-branch"
automatically.
git branch
-
--set-upstreamor-u- set the upstream branch to track for local branch you are on -
-vv- also output tracking branches (if local branch is tracking remote one), also if current branch is ahead or behind; does the comparison based on local references, thus dogit fetch --allto get up date information
git pull - is essentially git fetch followed by git merge.
git push <remote> --delete <branch> - delete a remote branch.
Setup: source branch checks out from target and does some work, while other work was done on target as well. Then source branch tries to perform rebase.
To perform rebase - checkout to source branch and type git rebase <target_branch>.
-
--onto <parent_a> <parent_b> <source_branch>- in the situation whenparent_bdiverged fromparent_aandsource_branchfurther diverged fromparent_buse the following to rebasesource_branchto theparent_a -
--continue- restart rebase after resolving conflicts -
--abort- abort the rebase operation
Operation: going to common ancestor, getting the diff introduced by each commit of the branch you are on, saving the diffs to temporary files, resetting the current branch to the same commit as the target branch, and applying each change.
Thus rebasing just replays the changes that took place in one branch in another
branch, while classic merge takes endpoint and merges them together. After
rebase is done the target branch can be simply fast-forwarded by git merge <source_branch>
Do not rebase commits that exist outside your repository and that people may
have based work on - golden rule; that is when you rebase you introduce new
commits, while abandoning other, while other commits may have been used by
others when they merged their work. Try to run git pull --rebase or git fetch ; git rebase <remote>/<branch> to let git try to rebase your work over rebase
other people have performed earlier (and your work was done on top of the old
commits that were abandoned because of that rebase). If new rebased commit is
nearly identical to the one that was on separate branch, git might be able to
successfully apply rebase of your branch as well.
Good rule of thumb is to rebase work you haven't pushed anywhere.
git merge-base feature main returns the commit hash of the parent commit on
main branch where feature branch work diverged from (base commit of feature
branch).
Git provides number of ways to refer to single commit, set of commits, or range of commits.
- Single revision
- 40-character full SHA-1
- short SHA-1 - can pass short version as long as its not ambiguous (no
other commit has it); pass
--abbrev-committogit logto output shorter versions (but still unique), defaults to 7, but gets longer to keep them unique - branch reference - the commit at the tip of the branch;
rev-parseis a low level operation that name resolves too -git rev-parse <branch_name>will output its SHA-1
- multiple revisions
-
-n <number>- limit output; for example,git log HEAD~4..HEADis same asgit log -n 4
-
Git keeps logs of where your HEAD and branch references have been in the last
few months (default is 90 days), which is a chronological listing of history and
performed actions); this information is strictly local and represents only local
changes/info. git reflog outputs this information in similar format to
git log --oneline. In case of hard reset, this command can be used to retrieve
dangling commit reference (move it back to current history with git cherry-pick).
git show <reference> - can refer to reflog data as well, examples below
(substitute <reference>:
-
HEAD@{5}- 5th entry fromgit reflog -
master@{yesterday}- using syntax to access specific dates
git log -g - see reflog info in git log output
Ancestry reference uses ^ (caret) symbol. If added at the end of a reference,
it is resolved to the parent of that commit - git show HEAD^ resolved to the
commit before current one. Can also specify number after caret to specify which
parent (useful for merge commits) - HEAD^2 - first parent is the branch you
were on when performing the merge, while second is the one that is merged.
Another ancestry reference is ~ (tilde). Always goes to the first parent, thus
HEAD~2 means first parent of the first parent. Two syntaxes can be also
combined HEAD~3^2
Double-dot syntax - shows range of commits that are reachable from one commit, but aren't from another, f.e.
A->B->E->F->master
|->C->D->experiment
git log master..experiment - will output D and C, while vice versa will return
F and E
git origin/master..HEAD - shows what commits are going to be pushed to the
server (can omit HEAD, git will substitute it)
^ or --not before any reference means do not show reachable commits from
that reference; can specify more than two reference (unlike 2 dot)
git log refA..refB is the same as git log ^refA refB and same as git log refB --not refA
Triple-dot shows commits that are reachable by either of the two references, but
not by both; --left-rght options helps to determined which commits are
reachable by which of the two references:
`git log master...experiment` returns F E D C
git log <since>..<until> - displays the commits reachable from <until> but
not from <since>.
git add [-i | --interactive] - interactive shell mode
Patch option lets you stage separate hunks of file. Patch option
[-p | --patch] also works with add, reset, checkout and stash save
commands
git stash or git stash push - stash changed files (dirty state) onto separate stack.
-
list- show the list of stashed files on the stack; following commands, if not specified the index, assume that operation is to be done on the top most item -
show- show stashed files and high-level summary on changes -
apply [--index] stash@{n}- apply the file in the current state (branch and directory); does not drop the file from stash stack;--indexflag tell git to apply it to the staging area; can passnto specify with file to apply -
drop stash@{n}- drop item from the stack -
pop stash@{n}- apply the stash and drop from stack -
--include-untrackedor-u- include untracked files -
--allor-a- include all files (also ignored ones) -
--patch- interactive stashing -
branch <new branchname>- create a new branch from a stashed work; creates new branch -> checks out the commit you were on -> applies stashed items -> drops the stash if applied successfully
git clean - removes untracked files irreversibly; safer option is to run
git stash --all
-
[-f]- force, "really do this" - required flag by Git, unless configuration variableclean.requiredForceis not set to false; second-fmight be needed if you try to removed submodules -
[-d]- remove directories that become empty as a result of clean command -
[--dry-run | -n]- show what would have been removed; that is put-ninstead of-fto inspect first -
[-x]- removed ignored files as well -
[-i]- interactive mode
git grep
Search within working directory or anywhere in the git history
-
--line-numberor-n- prints out line numbers where matches were found as well -
--countor-c- show summary with filenames containing the match and number of matches in each -
--break- break each file (insert new line after each file) output -
--heading- instead of starting each entry with the filename containing it, output filename on the separate line, then lines with the match add more
git log
-
-S <string>- output commits that changes the number of occurrences of provided string -G-
-L :<function>:<file_name>- line log search, git will try to figure out the bounds of the provided function and output the changes made to it throughout whole history; if git cant figure out the bounds, pass the regular expression, for the provided example it would begit log -L '/unsigned long function/',/^}/:file_name; can also pass range of lines or single line
All the following is preformed locally. Once the work is pushed to the server, it is completely different story.
git commit --amend - modify last commit message; opens configured editor
and loads it once editor is closed; can also be used to change the contents -
simply make changes, stage them and then perform the command. Commit hash is
always updated when running --amend.
-
--no-edit- avoid editor session (for example adding files or changes, and there is no need to change the message)
To change multiple commits use git rebase command with -i, for interactive,
option; do not specify the commits already on the server, because they will be
rewritten. The following example changes last 3 commits (could also specify
HEAD~2^); reference is the new base.
git rebase -i HEAD~3The command returns the list of commits (but in reverse order than git log):
pick f7f3f6d changed my name a bit
pick 310154e updated README formatting and added blame
pick a5f4a0d added cat-file
# Rebase 710f0f8..a5f4a0d onto 710f0f8
#
# Commands:
# p, pick <commit> = use commit
# r, reword <commit> = use commit, but edit the commit message
# e, edit <commit> = use commit, but stop for amending
# s, squash <commit> = use commit, but meld into previous commit
# f, fixup <commit> = like "squash", but discard this commit's log message
# x, exec <command> = run command (the rest of the line) using shell
# b, break = stop here (continue rebase later with 'git rebase --continue')
# d, drop <commit> = remove commit
# l, label <label> = label current HEAD with a name
# t, reset <label> = reset HEAD to a label
# m, merge [-C <commit> | -c <commit>] <label> [# <oneline>]
# . create a merge commit using the original merge commit's
# . message (or the oneline, if no original merge commit was
# . specified). Use -c <commit> to reword the commit message.
#
# These lines can be re-ordered; they are executed from top to bottom.
#
# If you remove a line here THAT COMMIT WILL BE LOST.
#
# However, if you remove everything, the rebase will be aborted.
#
# Note that empty commits are commented outGit will perform the specified commands from top to bottom(when you close the editor)
-
change commit message - change
picktoedit, git will stop there, perform usualgit commit --amend, continue withgit rebase --continue -
reorder commits - simply reorder / delete commit entries
-
squash commits - change
picktosquashon commit that you want to squash to previous one, in the following example last two commits are squashed into first; git then puts you into editor to merge commit messages (if want to push updated commits to remote finish withgit push --force-with-lease origincommand):pick <hash> commit message one squash <hash> commit message two squash <hash> commit message three -
split commit - change
picktoedit; git will perform parent commits and the one indicated aseditalso stop right after, then you cangit reset HEAD^and redo commit(s) finishing withgit rebase --continuewhen done
git filter-branch - rewrite large portions of history, though python script
git-filter-repo is recommended and can be found here
+ --tree-filter <shell_command> HEAD - runs specified shell command on
each checkout, and recommits the result
+ --all - run in all branches
+ --subdirectory-filter <directory> HEAD - makes the specified directory
a root directory for every commit; git also automatically removes all
commits that did not affect the subdirectory [NEEDS_CHECK]
+ --commit-filter - change the email in all commits, example below
(changes hashes of all commits, not just where the change applied)
shell git filter-branch --commit-filter ' if [ "$GIT_AUTHOR_EMAIL" = "schacon@localhost" ]; then GIT_AUTHOR_NAME="Scott Chacon"; GIT_AUTHOR_EMAIL="[email protected]"; git commit-tree "$@"; else git commit-tree "$@"; fi' HEAD
Commonly used to apply a bug fix for multiple versions/revisions or to capture some commits from inactive branch. Creates a copy of a referenced commit and applies it to head.
$ git checkout <reference> # where to apply the commit
$ git cherry-pick <commit_hash>3 trees (workspaces) that git system manages and manipulates:
- HEAD - pointer to the last commit on the branch(current branch reference)
- Index - proposed next commit(staging area)
- Working directory (working tree) - while previous two trees store contents in
.git, this one unpacks them so you can easily work with files; refer to this tree as sandbox, where you can try and do all the changes
Workflow goes as follows: |<--------(checkout the project)--|------------------HEAD |---------------------------------Index---(commit)-->| working directory--(stage files)->|------------------|
You make changes in the current working directory, then run git add, which
moves the modifications to staging area (Index), then git commit creates a
snapshot, which finally makes all trees to agree.
git reset (all options update HEAD reference)
-
--soft <reference>- changes (differences) are placed in the staging area. -
--mixed <reference>(default behavior) - changes are placed in the working directory;git reset HEAD~effectively unstages all files (practically opposite ofgit add) -
--hard <reference>- throws away all changes between current version and specified reference. Commit you moved from can be recovered from Git DB, but otherwise all data is overwritten; one way to retrieve overwritten commit is to find the commit ID using git reflog, checkout to that commit, create a branch and finally merge it with the original branch. Changes that were present in staging area and working directory are irreversibly gone.
git reset also accepts --patch option to unstage on a hunk-by-hunk basis.
git reset file-path behaviour matches committed snapshot (reference) and
Index (staging area); example below unstages specified file (does not alter
Working direcroty or move the current branch):
shell $ git reset HEAD <file>
git checkout file-path behaviour matches commited snapshot and Working directory; example below reverts an individual file to match the specified commit without switching branches ```shell $ git checkout
# Drop current changes in working directory
$ git checkout HEAD <file>
```
Overall workflow is as follows: developer creates a topic branch, makes changes, sends patches to repository maintainer, who incorporates patches to the local topic branch, then merges it with local stable branch and then publishes updated branch to the remote. Other developers, including the author of the change can then fetch updates from remote.
git format-patch
Creates a file (gitsendmail format) to re-create a commit.
# Creates patches for all commits not present on the branch_name
$ git format-patch <branch_name>git send-mail
Takes the patches specified on command line and sends them out. Documentation
git am
Applies patch file to the current branch, effectively recreating the commit.
$ git am < <name>.patchTree object is Git's representation of the "snapshots". They record state of a directory at any given point notion of time or author. Each tree object is then wrapped into commit object with a parent reference, which is just another commit. Tree contains blobs and may also contains other trees, which are folders. Blob object contains plain data file. Name of the file is stored in a tree object that contains the blob, not in the blob itself. Tag object is simply a reference to a commit object.
All Git objects have associated SHA checksum, which gives each object unique identification and ensures it's contents aren't corrupted. Since same file would produce same checksum, Git shares blobs across trees, instead of duplicating them (when contents of the file has not changed). As soon as anything has changed in a file, new blob is created.
git cat-file
Show information on Git objects - one of commit, tree, blob, or tag.
-
-t- show object type, f.e.git cat-file -t master -
-p- pretty print the object, e.ggit cat-file -p <hash>
$ git cat-file commit HEADgit ls-tree
Display a pretty version of the specified tree object (use ID from git cat-file command).
$ git ls-tree <ID>All Git objects are stored in .git/objects and split across directories,
based on first 2 letters of a SHA checksum (f.e. 7acjsu3192 would reside in
directory 7a). The remaining of a checksum is used as a filename.
As repository grows Git may automatically transfers object files into a more compact form, pack file. Garbage collection is done by compressing individual object files into faster and pack file and by removing dangling commits (deleted, unmerged branches, etc).
git gc
Perform garbage collection on the object database.
-
git index-update
Stage the specified file.
-
--add- used for adding new files
$ git index-update index.html $ git index-update --add new_item.html
-
-
git write-tree
Generate a tree object from an Index and store it in object database. Returns the ID of the new tree object.
-
git log --oneline -n 1- find out commit ID of the parent -
git commit-tree
Create a commit object from the given tree object and parent commit. It also waits for input that will be used as commit message (use
Ctrl-Dto send "End-of-file" character to end the input). Returns the ID of the new commit object.$ git commit-tree <tree_id> -p <parent_commit_id>
-
update branch reference - got to
.git/refs/heads/branch_nameor to.git/packed-refs, if previous file is not present (meansgit gcwas run or Git did it automatically)
Saves current snapshot omitting .git directory. Format can be zip or tar.
$ git archive <branch_name> --format=zip --output=<file_name>.zipTurns repository into a single file with the versioning information of the
entire project. Similar to pushing a branch to remote. Resulting file can even
be used in git clone command.
$ git bundle create <file_name>.bundle <branch_name>
$ git clone <file_name>.bundle -b <branch_name>Git hooks are scripts that can run when particular event occurs, such as new
push. Samples are located under git hooks directory.
- bisect command which is used to find where "the feature" was broken first
- can pass the script to check it
- git stash push path/to/file - stash individual file
- git stash -p - ask before every stash
- resolving merge conflicts
- rewriting history
View introduced changes
$ git log start..end --stat
$ git log HEAD~4..HEAD --statMake history changes (squashing, changing commit messages, etc) in the development branch (forked from main); substitute master to target branch name
$ git rebase -i masterIn case of working on outdated branch and trying to push changes to remote, first, fetch changes, then rebase on remote:
$ git fetch origin
$ git rebase origin/master
$ git push origin master