🥇 Git rapid experience
Git belongs to a family of version control systems that are referred to as “distributed.” In a distributed system, everyone who clones a repository gets a full copy of the repository.
âš“ The three stages of Git
Untracked file – git does not have history about it - only exists in working directory
Tracked file – a file git cares about
Staged file – a file added to the index area (staged) - git started to care by tracking it
Unmodified file – a file moved from staging area to commit object database
Modified file – a file edited after being stored in the database
🎂 Essential commands on git instructions
git status
- query repository and display history information - in no way affects the repository
git init
- initialize local git repository
more details
The command creates hidden directory .git with hidden config files and commit objects repository to save changes snapshots. On defaults creates a working branch, named master or main, depending on the git version (older versions use master)git add <filename>
- git makes a copy of a file and puts it in the index area - the index is a place to temporarily house changes - terminologically, the index is the “staging area” that hosts objects before storing them into the repository.
git commit [-m <msg>]
- records changes to the repository
more details
It takes the content of the staging area and stores it in the database. When we commit, git creates a commit object that records the state of the index in its memory. Changes are stored in object database. Each object has a reference to the changes together with information as timestamp, hash id, author etc.🌴 Branching
The branch represent line of work, independent of other branches. Following good practice, generation of branches follows new features, resolving issues or experimental workspace. Each branch contains changes snapshots - commits. For navigation through git tree, braches and commits, the user location is regulated with HEAD reference. Where HEAD points, there you are :)
git switch [-c | --create] <branch name>
- switch on a specified branch - with parameter –create, create a new branch and switch to it in one fell swoop.
git branch [-a] [-v] [-d] [-D] [-m] [-vv] <name>
- create a new branch - best practice name for branch includes: _
- [-a] - show all branches
- [-v] - show all branches with top commit hash id
- [-d] - delete a branch
- [-D] - force delete
- [-m] - rename a branch
- [-vv] - very verbose
git merge <branch-name>
- takes changes from the branch _
HEAD~1 references the first parent of the commit you are on (remember commit reference each other in child -> parent relationship. Thus build asymmetrical tree). HEAD~2 means the parent of the parent of the commit you are, and so on and so forth. Git offers another operator that works with HEAD: the caret (^), which helps when you’re navigating from commits with multiple parents (merge commits)
HEAD^1~2 – navigate to first parent, find the parents parent
Listing repo
git log [--abbrev-commit] [--oneline] [--all] [--graph]
- lists all the commits in the current branch, with the latest commit at the top, followed by its parent, and so on.
- [–abbrev-commit] - shows shortened hashes
- [–pretty=oneline] - shows commits’ info in a line
- [–all] - displays all branches in the repository
- [–graph] - displays the commits as a graph
git diff [--word-diff] [--cached | --staged] <commit> <commit>
- find the difference between lines of committed files
more details
The git diff command is always comparing two sets of changes, which can be visualized by a Venn diagram. The first argument is the set on the left (always indicated by “a/”) and prefixed with a minus (“-”). The second argument is the set of the right, indicated by “b/”, and prefixed with a “+”.- [–word-diff] - shows how individual words differ rather than how lines differ
- [–cached | –staged] - tells git to compare the content of the object from database with those in the index
Fixing mistakes by undoing
git restore [--staged]
- discards any changes in the working directory.
- [–staged] - moves files from staged state to unstage
Git commits are immutable. That is, once you create a commit, that version of the commit is preserved. Any edits to the commit (like amending it) will create a new commit that replaces the old commit in your history.
git rm [-r] [--cached]
- removes tracked files from the working directory and from index
more details
Versions of the file that were previously committed remain as they were in the object database. This is because a commit represents the changes you made at the time of the commit. If a file existed at the time a commit was made, the commit will remember that for as long as the repository exists.git mv
- renames or moves the files you tell it to in both the working directory and the index
Git allows for editing commit messages using the git commit command, with a special flag called –amend. git commit –amend -m “message> The first thing to check is that you are on the same branch as the commit you wish to edit (you need to have a clean working directory).
🏴 Undoing commits
git reset [--soft] [--mixed] [--hard]
- has two immediate effects —it moves the HEAD and the branch to the commit you specify
- [–soft] - takes the edits you committed and moves them back into the index, and then from the index it copies those changes into the working directory alone.
- [–mixed] - does a bit more work than the –soft mode does. It has two steps:
- Moves the changes in commit B (the commit you are undoing) into the index, and then copies those changes from the index into the working directory, just like –soft mode does.
- It then copies the contents of commit A into the index. That is, the index now looks exactly like the commit you just reset to.
- [–hard] - takes what the –mixed mode does to its logical end. In mixed mode, the second step copies the contents commited in “A” into the index, and stops there. –hard mode does not. It takes the contents of the index (which have the changes as they are in commit A) and overwrites the working directory. This means that the object database, the index, and the working directory all look the same. It’s as if commit B never happened! After a hard reset, the working directory, the index, and HEAD all point to commit “A.”
git revert
- is to be given the ID or reference of the commit you want to undo - looks at the changes introduced in B and calculates the anti-commit - this is an actual commit that Git will prepare -you are not erasing commits - rather, you are adding new commits.
🤿 Working with remotes
The remote repository and the local copy are completely independent of one another
git fetch [-p | --prune] <repository_name> <branch>
– updates the remote tracking branches and info on the latest commits
- [-p | –-prune] - lean up all remote tracking branches that no longer have a remote counterpart
Remote tracking braches origin/
cannot be switched or changed, they serve git as a reference to what is happening to remote
git pull
– copies the remote repository to local repository - git pull is git fetch + git merge
git remote -v
– print name of the remote repository, url and push or fetch actions
git config –global push.default <branch_name>
- set the name of a branch to push on default without specifying it - default is master
git push
– pushes changes to remote - name of remote repository is origin - git knows where to push because the git clone records the URL of the remote - change remote with config
When you attempt to push a branch to the remote, git tries to figure out exactly which remote branch it should update. But if the branch is brand new, Git won’t see a counterpart in the remote.
git push –set-upstream origin <new_branch_name>
đź’ş Searching repos
git blame <file-name | commit-id>
- annotate any tracked file in a the repository - shows, on a per-line basis, details about the latest commit that changed that line, including the commit ID, the author info, and the date the change was made.
git grep [-i | --ignore-case] [-n | --line-number]
- search the contents of all tracked files in repository (default is case-sensitive).
- [-i | –ignore-case] - search case-insensitive.
- [-n | –line-number] - display the line number for a match.
- [-n | –line-number] - display the line number for a match.
- [-l | –name-only] - list just the names of the files.
- [-S | –name-only] - list just the names of the files.
git log [-S] [-p | --patch] [-G]
- shows the commit logs
- [-S] - find which commit added or removed a piece of text - search the entire commit history - limit to inspect the history of a single file by supplying the name of the file.
- [-p | –patch] - display the patch introduced in every commit using the -p (shorthand for –patch) flag. This can be combined with the -S flag to see if the search text was added or removed in a particular commit.
- [-G] - find all commits where the line that contains a piece of text changed
git checkout <commit-id
- “flip back” to any commit in your commit history - will rewrite your working directory to look like it did when you made that commit.
Checking out a commit puts you in “detached HEAD” state. This means that you are no longer working on a branch. You can continue to make editions and commits, but switching away from that commit history means you will abandon your commits (since they are not referenced by a branch). It’s best not to make any commits when you are in detached HEAD state. Always work on branches.
git bisect <commit-id>
- you can search for commits that introduced a typo or a bug using the git bisect command, which uses the binary search algorithm to navigate your commit history, and quickly zero in on the commit you are looking for.
At each step in a git bisect session, Git checks out a commit, leaving you in detached HEAD state. Since Git will rewrite your working directory, you can look around to see if you spot the unwelcome behavior. Depending on whether you see the issue, you can tell Git if the current commit is “good” or “bad”, which informs Git which direction in the commit history to search for. This repeats till you’ve isolated the commit with the reported issue
Configuring git
Git is extremely customizable. You can set and override many settings using the git config command.
git config --global
- allows to create settings that affect every repository you work in on that particular workstation.
All global settings are stored in a file called .gitconfig, which is stored in the home directory under your account. It consists of sections and keys under a section, each associated with a value. You’ll have to configure some settings, like user.name and user.email, to be able to use Git. Others, like core.editor, override Git’s defaults and are optional.
git config --local
- store certain settings at the repository level, that is, local to a specific repository.
git config --list
- list all settings.
Most, if not all, projects require that some files never be committed. You can tell Git to ignore an untracked file. Once ignored, it will remain forever untracked. To tell Git to ignore a file, create a .gitignore file at the root of your repository that lists all the files you wish to ignore.
“Commit early, commit often” is the mantra when it comes to working with Git. Recording snapshots of your work regularly is a good habit to develop. Think of each commit in terms of its scope, not its size. Try to group changes together logically.
Use consistent and informative commit messages. This can be helpful when reading the output of the git log command or searching for a commit using git bisect.
Create contexual and meaningful branch names that help discern which branches are yours and what their purposes are.
🏸 Something more advance
git tag [-l | --list]
- record thes current ID (that is, where HEAD points to) in the tag. However, you can supply a specific commit ID after the tag name. _git tag 2.0.0
- [-l | –list] - list all the tags in the repo
git cherry-pick <commit_id>
- copy a commit to another branch
git stash
– stash your changes, git stuffs them away in a special location - leaves your working directory clean to switch branches - think of a stash as a sort of pseudo-commit
The difference between stash and commit is that stashing records the changes in both your working directory and the index, as opposed to a commit, which only records what is in your index. The other difference is that a commit adds to your commit history, while a stash does not. If you push, your stashes don’t go along for the ride, they remain in your local Git repository.
git stash pop –index
- to return changes from stash stack
git reflog
- maintains a log called the reflog, (short for reference log) that is updated every time HEAD moves
git rebase
- rebasing “flattens” the history—you end up with a straight line. Rebases new branch on top of the master branch commit.
This will tell git you want to start ignoring the changes to the file
git update-index --assume-unchanged <path/to/file>
When you want to start keeping track again
git update-index --no-assume-unchanged path/to/file
git log --follow --all -p <path/to/file
- displays commits info that introduces changes on the file