It is a free and open-source version control system used to handle small to very large projects efficiently.
Git is used to tracking changes in the source code, enabling multiple developers to work together on non-linear development.
The Linux kernel is an open source software project of fairly large scope. During the early years of the Linux kernel
maintenance (1991–2002), changes to the software were passed around as patches and archived files. In 2002, the Linux kernel
project began using a proprietary DVCS called BitKeeper. In 2005, the relationship between the community that developed
the Linux kernel and the commercial company that developed BitKeeper broke down, and the tool’s free-of-charge status was revoked.
This prompted the Linux development community (and in particular Linus Torvalds, the creator of Linux) to develop their own tool
based on some of the lessons they learned while using BitKeeper. In 2005, the Linux kernel community began using Git as their
version control system, and other open-source projects soon followed.
-
SCCS (Source Code Control System) - 1972. Version control system designed to track changes in source code and other text files during the development of a piece of software. It was originally developed at Bell Labs beginning in late 1972 by Marc Rochkind for an IBM System/370 computer running OS/360. Only single user can work simultaneously on SCCS. Only for Unix
-
RCS (Revision Control System) - 1982. Is an early implementation of a version control system (VCS)
It is a set of UNIX commands that allow multiple users to develop and maintain program code or documents. With RCS, users can make their own revisions of a document, commit changes, and merge them. RCS was originally developed for programs but is also useful for text documents or configuration files that are frequently revised. -
CVS (Concurrent Versioning System) - 1986. Is a version control system originally developed by Dick Grune in July 1986. CVS operates as a front end to Revision Control System (RCS), an earlier system which operates on single files. It expands upon RCS by adding support for repository-level change tracking, and a client-server model. Several users can work simultaneously on CVS.
-
SVN (Apache Subversion) - 2000. Software developers use Subversion to maintain current and historical versions of files such as source code, web pages, and documentation. Its goal is to be a mostly compatible successor to the widely used Concurrent Versions System (CVS).
Features:
-
Native support for binary files, with space-efficient binary-diff storage
-
The system maintains versioning for directories
-
Branching is implemented by a copy of a directory, thus it is a cheap operation, independent of file size
-
-
Git - 2005.
Features:
-
Distributed version control system
-
Reliable: providing a central repository that is being cloned each time a User performs the Pull operation, the data of the central repository is always being backed up in every collaborator’s local repository
-
Git is compatible with all the Operating Systems that are being used these days
-
Non-linear Development: allows users from all over the world to perform operations on a project remotely
-
Speed
-
Open-Source
Contra:
-
Not good with big binary file
-
Movies, images...
-
A distributed version control system enables every user to have a local copy of the running history on their machine, so if there's an outage, every local copy becomes a backup copy and team members can continue to development offline. There is no main repository.
Git is a version control system, GutHub is a service for hosting of the Git repositories.
--local: For writing options: write to the current repository .git/config file. This is the default behavior.
--global: Global level configuration is user-specific, meaning it is applied to an operating system user.
--system: System-level configuration is applied across an entire machine. This covers all users on an operating system and all repos.
One of the first things you did was set up your name and email address:
```
$ git config [--global | --local | --system] user.name "John Doe"
$ git config [--global | --local | --system] user.email johndoe@example.com
```
other useful setting is text editor to prompt for further input. For VS Code use:
```
git config [--global | --local | --system] core.editor "code -"
```
You can edit .git/config file manually with any text editor:
```
[core]
repositoryformatversion = 0
filemode = false
bare = false
logallrefupdates = true
symlinks = false
```
Get all config file entries: git config --list [--global | --local | --system]
Introduce file or folders to exclude from a project. These files will not be affected by Git commands bit will be exist in working directory.
git init create an empty Git repository or reinitialize an existing one. It can be used to convert an existing, unversioned project to a Git repository or initialize a new, empty repository. Most other Git commands are not available outside of an initialized repository, so this is usually the first command you'll run in a new project.
Executing git init creates a .git subdirectory in the current working directory, which contains all of the necessary Git metadata for the new repository. This metadata includes subdirectories for objects, refs, and template files. A HEAD file is also created which points to the currently checked out commit.
--- git init --bare
Initialize an empty Git repository, but omit the working directory.
Shared repositories should always be created with the --bare flag. The --bare flag creates a repository that doesn’t have a working directory, making it impossible to edit files and commit changes in that repository. You would create a bare repository to git push and git pull from, but never directly commit to it.
Git however uses a three-tree architecture:
-
Repository (being tracked by Git)
-
Staging index (containing changes that are about to be committed into the repository)
-
The Working Tree (containing changes that may not be tracked by Git)
We added, then we committed, it was a two-step process. When we made our first commit, we didn’t just perform a commit. First, we used the add command. We added, then we committed. It was a two-step process (added our files to the staging index, and then from there we committed to the repository).
The commands: git add, git status, and git commit are all used in combination to save a snapshot of a Git project's current state: There are simple three steps for the main flow:
Make changes => Add the changes => Commit changes to the repository with a message
Commit is the way to save changes to a branch. The snapshot of the current state is created.
The commit object contains a tree of blob objects and other objects which represent the commit (snapshot).
The snapshot can be used to revert branch to that state.
In Git, every commit you make is assigned a unique SHA-1 hash value. This hash value is like a fingerprint for each commit.
It helps Git keep track of every change made in the repository. Git uses a specific type of hash value known as SHA-1.
Every time you commit changes, Git generates a unique hash value.
This value is a SHA-1 hash of the commit’s contents, including its code changes and metadata(author, date, commit message...)
Think of these hash values as unique IDs. They allow Git to track each commit individually.
This tracking is what enables Git’s powerful version control capabilities.
Summarize:
-
Gite generates a checksum for each change set. Checksum algorithms convert data into a simple number. The sama data always equals same checksum
-
Data integrity is fundamental. Changing data will change checksum.
-
Git uses SHA-1 hash algorithm to create checksums: 40-character hex string.
git commit –allow-empty -m “message”
HEAD can be termed as a special ref that points to the current commit. However, HEAD can change depending on the latest commit that we have checked out in our git directory.
git show HEAD
- To verify the HEAD status use this command and it will also show the HEAD location.
We can check out our HEAD in the .git/HEAD file. It will contain, for ex:
ref: refs/heads/main
In rare cases, the HEAD file does NOT contain a branch reference, but a SHA-1 value of a specific revision. This happens when you checkout a specific commit, tag, or remote branch. Your repository is then in a state called Detached HEAD
Create a new branch from the detached HEAD state.
Show commit logs. The output is given in reverse chronological order by default.
-n : Limit the number of commits to output
--since= --after=: Show commits more recent than a specific date
--until= --before=: Show commits older than a specific date
--author= --committer=: Limit the commits output to ones with author/committer
--grep=: Limit the commits output to ones with a log message that matches the regular expression
--graph: Displays the commits history in graphical view
... many others...
--oneline: This is a shorthand for "--pretty=oneline --abbrev-commit" used together
... many others...
Manage reflog information.
Reference logs, or "reflogs", record when the tips of branches and other references were updated in the local repository.
Reflogs are useful in various Git commands, to specify the old value of a reference.
git reflog --all
: Show of all changes made to repo.
The git status command displays the state of the working directory and the staging area. It lets you see which changes have been staged, which haven't, and which files aren't being tracked by Git. Status output does not show you any information regarding the committed project history.
--short: Give the output in the short-format.
Diffing is a function that takes two input data sets and outputs the changes between them. git diff is a multi-use Git command that when executed runs a diff function on Git data sources. These data sources can be commits, branches, files and more.
Branch1 <=> Branch2 : git diff <branch> <branch>
Commit1 <=> Commit2 : git diff sha1 sha2
Working tree <=> Staging area : git diff
Staging area <=> Repository : git diff --staged | --cached(legacy)
```
git diff
diff --git a/diff_test.txt b/diff_test.txt
index 6b0c6cf..b37e70a 100644
--- a/diff_test.txt
+++ b/diff_test.txt
@@ -1 +1 @@
-this is a git diff test example
+this is a diff example
```
git -rm - Remove files from the working tree and from the staging area. This command is opposite to add
rm --cached: removal should happen only on the staging area.
-r: Recursively removes folders
--dry-run: only see an output of the files that Git would remove, but no files are actually deleted.
git mv - Move or rename a file, a directory, or a symlink
git clean: Remove untracked files from the working tree
Cleans the working tree by recursively removing files that are not under version control, starting from the current directory.
-f: forces the removal of untracked files. Directories and ignored files are left alone
-d: forces removal of untracked git directories
-x: removes untracked files that map to .gitignore entries.
-i | --interactive: Show what would be done and clean files interactively
-n |--dry-run: Don’t actually remove anything, just show what would be done
git restore: Restore working tree files, --worktree flag can be added, but it is by default.
git restore <file>
: remove all the changes that are not staged for commit.
Or you can use old command: git checkout -- <file>
git restore --staged: Specifying --staged will only restore the staging area.
git restore --staged <file>...
Note: Specifying --staged AND --worktree: restores both working tree and staging.
Or you can use reset command: git reset HEAD <file>...
git commit --amend
Replace the head of the current branch by creating a new commit.
Previous commit will be deleted, new commit with the new SHA1 will be created.
--no-edit: do not ask to write(change) commit message
git update-index –assume-unchanged <filename>
Or you can use old command: git chechout SHA1 <file>...
git revert
: Revert some existing commits.
This requires your working tree to be clean (no modifications from the HEAD commit). Note: git revert is used to record some new commits to reverse the effect of some earlier commits (often only a faulty one).
If you want to throw away all uncommitted changes in your working directory, you should see git reset
Reset current HEAD to the specified state. The git reset command is a complex and versatile tool for undoing changes.
--soft: do not change staging index and working tree. Reset only repository, come back only for one command(commit)
--mixed(default): changes staging index to match repository, does not change working directory, come back for two commands(commit, add)
--hard: changes staging index and repository and working folder. come back for all 3 commands(commit, add, changes in working tree)
git clone Clone a repository into a new directory
Clones a repository into a newly created directory, creates remote-tracking branches for each branch in the cloned repository, and creates and checks out an initial branch that is forked from the cloned repository’s currently active branch. Local repositories also can be cloned.
git clone -b <branch> --single-branch repository-url branch
: clone only songle branch
--depth <depth>
: clone only last M commits
git stash : Stash the changes in a dirty working directory away
-
push: Save your local modifications to a new stash entry and roll them back to HEAD (in the working tree and in the index)
-
pop: Remove a single stashed state from the stash list and apply it on top of the current working tree state
-
apply: Like pop, but do not remove the state from the stash list
-
list: List the stash entries that you currently have
-
clear: Remove all the stash entries
-
u: Add untracked files to the stash also
-
a: Add files from .gitignore to the stash also
-
drop: Remove a single stash entry from the list of stash entries
git stash save "name"
: store stash with the name.
git checkout <stash-id> -- <filename>
: get from exact stash exact file
Merge can be fast-forward – target branch is updated to the latest commit of the source branch
or three-way merge: branch histories are combined into a new commit.
-
Merge: creates a new “merge commit” in the feature branch that ties together the histories of both branches.
Pro: Merging is nice because it’s a non-destructive operation. The existing branches are not changed in any way. This avoids all of the potential pitfalls Contra: Feature branch will have an extraneous merge commit every time you need to incorporate upstream changes. If main is very active, this can pollute your feature branch’s history quite a bit.
-
Rebase: moves the entire feature branch to begin on the tip of the main branch, effectively incorporating all of the new commits in main.
Pro: you get a much cleaner project history. This makes it easier to navigate your project with commands like git log Contra: Rebase makes you resolve conflicts in the order they were created to continue the rebase. Unfortunately, this means more work for you, as you may need to fix the same conflicts repeatedly
Occurs when two branches have made changes to the same lines in a file OR one branch deletes a file and another modifies it. The developer must manually resolve the conflicts.
It is the way to isolate development work on a separate task (new feature or bugfix). The changes in branch will not affect to main master branch (or other branches).
```
git branch <name>
git switch <name>
```
git branch –d <name>
: Delete local branch (not active for now)
git branch –D <name>
: Delete local branch which is not fully merged
git push –d origin <name>
: Delete remote branch
git -m <newname>
: Rename current branch
git -m <oldname> <newname>
: Rename other branch
git branch –u remote/branch <local>
https://learngitbranching.js.org/
git remote
: List of short names
git remote –v
: List of short names + URL (fetch + push)
git branch –r
git pull: fetch AND integrate changes to current active branch
git fetch: downloads updates from a remote to your local without integrating them to local branches.
GitFlow – master branch, develop branch, feature branches, hotfix branches, release branches.
git branch –contain <sha1>
Git LFS is a Git extension for working with large files in a separate Git repository.
List the content of the given tree object: git ls-tree –r HEAD
They are scripts that are executed after a specific event occurs in a Git repository.
Server/Client hooks: inside .git/hooks folder.
For example: hook commit-msg to check commit message on client side.
Tool for managing Git repositories with Subversion history. It allows you to keep Subversion history while moving to Git. It will help you to migrate from SVN to Git.
gitattributes - Defining attributes per path. A gitattributes file is a simple text file that gives attributes to pathnames.
Use the .gitattributes file to declare changes to file handling and display, for ex:
-
Collapse generated files in diffs
-
Create custom merge drivers.
-
Create exclusive lock files to mark files as read-only.
-
Change syntax highlighting in diffs.
-
Declare binary file handling with Git LFS.
-
Declare languages used in your repository.
Create git archive from current working tree.
Make binary search in the commits history. Steps:
-
git bisect start
-
Check HEAD commit and set as bad: git bisect bad
-
Check commit and set as good: git bisect good
-
git starts binary search – somewhere between bad and good, make checkout and you can test this commit.
-
If it’s still bad – tell git about it: git bisect bad OR git bisect good
-
After all call git bisect reset
Tag marks an important point in a repository’s history. Git supports two types of tags:
-
Lightweight tags point to specific commits, and contain no other information. Also known as soft tags. Create or remove them as needed.
git tag <name>
-
Annotated tags contain metadata, can be signed for verification purposes, and can’t be changed.
git tag –l
: list of tags
git show <tagname>
By default tags will not be pushed to origin, must push with flag –tags: git push –tags
git remote set-url <renotename> <remoteurl>
Submodules enable of the Git repo within the another as a subdirectory. For ex: integrating external project or lib into your project.
git submodule update -remote
: Fetch and update your submodules
Alias is synonymous with a shortcut. It is important to note that there is no direct git alias command. Aliases are created through the use of the git config command and the Git configuration files. As with other configuration values, aliases can be created in a local or global scope.
git config --global alias.co checkout
The git prune command is an internal housekeeping utility that cleans up unreachable or "orphaned" Git objects.
Unreachable objects are those that are inaccessible by any refs.
Any commit that cannot be accessed through a branch or tag is considered unreachable.
Prune is considered a garbage collection command and is a child command of the git gc command
The git gc command is a repository maintenance command. The "gc" stands for garbage collection. Executing git gc is literally telling Git to clean up the mess it's made in the current repository. git gc is a parent command and git prune is a child. git gc will internally trigger git prune. git prune is used to remove Git objects that have been deemed inaccessible by the git gc configuration.
Shows one or more objects (blobs, trees, tags and commits).
-
For commits it shows the log message and textual diff. It also presents the merge commit in a special format as produced by git diff-tree --cc.
-
For tags, it shows the tag message and the referenced objects.
-
For trees, it shows the names (equivalent to git ls-tree with --name-only).
-
For plain blobs, it shows the plain contents.
To search the commit log (across all branches) for the given text: git log --all --grep='Build 0051'
To do so while ignoring case in the grep search: git log --all -i --grep='Build 0051'
A pull request servers as a mechanism for contributing to a project hosted on GitHub.
Developer did modifications within own branch, uploads changes to a repo and then make a pull request.
Other developers examine the proposed changes, discussed them and then integrate the pull request to main branch.
Show what revision and author last modified each line of a file.
git blame .gitignore
git merge --squash
allows you to create a single commit on top of the current branch whose effect is the same as merging another branch.
git rebase -i <sha1>
combine multiple commits into one
Apply the changes introduced by some existing commits. Move commits to another branch. Pick up certain needed commits from one branch and apply them to another branch. If you want to apply some important commits(s) and not the whole branch, SHA1 will be changed.
-
Apply hot fix (single commit) from branch to master.
git switch master git cherry-pick <sha1>
--edit : need to edit the commit message
--no-commit: move changes to working directory, if you want to add smth after applying cherry-pick
- Move one commit from other branch to your current branch.