Summary
Highlights
Git is the most popular distributed version control system (DVCS) globally. It tracks changes to code over time, allows looking at project history, and reverting to earlier states. Unlike centralized VCS, Git provides every team member with a full copy of the project history, enabling local work and easier synchronization. Git is free, open-source, fast, and scalable, making branching and merging efficient, unlike other systems. It's an essential skill for software developers.
Git can be used via the command line, which is often the fastest and easiest method. Most modern code editors and IDEs, like VS Code, offer built-in Git support and extensions (e.g., GitLens). Dedicated graphical user interface (GUI) tools like GitKraken (personal favorite, cross-platform) and SourceTree (free for Windows/Mac) also exist. While GUIs are helpful, the tutorial focuses primarily on the command line due to its ubiquity and the limitations of GUI tools, which often require command line intervention for advanced tasks. The course will demonstrate both command line and GUI usage in VS Code and GitKraken.
Before starting, verify Git installation by typing 'git --version' in the terminal. If not installed or outdated, download the latest version from git-scm.com. Windows users are encouraged to use Git Bash for a Unix-like experience. Initial Git configuration involves setting user name ('git config --global user.name'), email ('git config --global user.email'), and default editor ('git config --global core.editor'). These settings can be edited via 'git config --global -e'. A critical setting is 'core.autocrlf' to handle line endings consistently across different operating systems (true for Windows, input for Mac/Linux) to avoid issues when collaborating.
To get help on Git commands, users can Google 'git [command name]' for full documentation. Alternatively, use 'git [command name] --help' in the terminal for comprehensive manual pages, or 'git [command name] -h' for a quick summary of options. A cheat sheet of all commands covered in the course is available for download.
Snapshots of a project are fundamental in Git. To start, create a project directory and initialize a new Git repository within it using 'git init'. This creates a hidden '.git' subdirectory where Git stores project history. This directory should not be manually modified. Removing it deletes the project's entire Git history. The presence of ' (git)' in the terminal prompt indicates an initialized Git repository. Optional tools like Zsh on Mac or Posh-Git on Windows can enhance the terminal's appearance.
The basic Git workflow involves modifying files, adding them to the 'staging area' (or index), reviewing changes, and then 'committing' them to the repository. The staging area holds proposed changes for the next snapshot, allowing selective commits. After initializing a repo, files are added to the staging area with 'git add', then committed with 'git commit -m "message"'. Each commit is a complete snapshot of the project, not just deltas, and includes a unique identifier, author, date, and message. Git is efficient in storage by compressing and not duplicating content.
To add files, first create them (e.g., using 'echo'), then use 'git status' to see untracked files. Use 'git add [filename]', 'git add *.txt', or 'git add .' to add files to the staging area. The 'git add .' command adds all new and modified files in the current directory and subdirectories. Once files are staged, they appear in green when running 'git status'. If a staged file is modified, the new changes are not automatically staged; 'git add' must be run again to capture the latest changes.
After staging changes, commit them using 'git commit -m "short message"'. For longer descriptions, use 'git commit' without '-m' to open the configured editor, allowing a short subject line and a detailed body, separated by a blank line. Comments (lines starting with '#') are ignored. Upon successful commit, Git provides statistics on changed files and insertions/deletions. The terminal indicator returns to green, signifying a clean working directory where the content matches the last commit.
Commit often, but ensure commits are not too big or too small. Each commit should represent a logically separate set of changes; don't mix unrelated changes. Develop a habit of creating meaningful commit messages, typically using the present tense (e.g., 'Fix bug' instead of 'Fixed bug'). Consistency in message style across a team is important.
While not recommended for most cases, it's possible to skip the staging area by using 'git commit -a -m "message"'. The '-a' flag automatically stages all modified (but not new or deleted) files and commits them in one step. This should only be done when confident that all changes are ready for commit without prior review, as the staging area's primary purpose is to allow careful review.
To remove a file from both the working directory and the staging area, use 'git rm [filename]'. If a file is first removed using the system's 'rm' command, 'git status' will show it as a deleted but unstaged change. In such cases, 'git add [filename]' or 'git rm [filename]' specifically for the deletion, or 'git rm [filename]' will remove it from staging and the working directory. Afterwards, commit the change: 'git commit -m "Remove unused code"'.
Renaming or moving files with system commands (e.g., 'mv' in Unix) results in a deleted old file and an untracked new file in 'git status'. To properly rename/move files while maintaining Git's tracking, use 'git mv [oldname] [newname]'. This single command renames/moves the file in both the working directory and the staging area, and Git intelligently recognizes it as a rename operation. The change can then be committed.
To prevent Git from tracking certain files or directories (e.g., logs, compiled binaries), create a '.gitignore' file at the root of the project. List patterns (e.g., 'logs/', '*.log') in this file. The '.gitignore' file itself should be committed to the repository. If a file or directory was accidentally committed before being added to '.gitignore', it must be removed from the staging area using 'git rm --cached [file/directory]'. For directories, use '-r' for recursive removal (e.g., 'git rm --cached -r bin/'). After removing from cache, commit this changes, and Git will stop tracking it.
The 'git status -s' (short status) command provides a concise overview of the working directory and staging area. It displays two columns: the left represents the staging area, and the right represents the working directory. Indicators ('M' for modified, 'A' for added, 'D' for deleted, '??' for untracked) show the state of files, allowing for quick checks of changes.
Before committing, always review staged changes. The 'git diff --staged' command displays changes in the staging area that will be included in the next commit. The output details file names, metadata, and a diff legend (minus for old content, plus for new content). 'git diff' without arguments shows unstaged changes (differences between the working directory and the staging area). Understanding this output is crucial, even when using visual tools.
Visual diff tools make comparing files easier. To configure Git to use VS Code as a default diff tool, set 'git config --global diff.tool vs-code' and 'git config --global difftool.vs-code.cmd "code --wait --diff \"$LOCAL\" \"$REMOTE\""'. Then, use 'git difftool' (for unstaged changes) or 'git difftool --staged' (for staged changes) to launch the visual diff viewer. While powerful, many modern IDEs provide integrated diff viewing, reducing the need for separate diff tools.
The 'git log' command displays the commit history, sorted from newest to oldest. Each commit entry includes a unique 40-character SHA-1 hash, the HEAD pointer to the current branch (e.g., 'master'), author, date, and commit message. 'git log --oneline' provides a condensed view with a shortened SHA and the first line of the message. The '--reverse' option can change the sort order. Later sections will delve deeper into browsing history.
To see the exact changes in a specific commit, use 'git show [commit_id]' or 'git show HEAD~N' where 'N' is the number of commits back from HEAD. This shows the commit details (author, date, message) and a diff of the changes. To view the full content of a file at a specific commit, use 'git show HEAD~1:path/to/file'. To see all files and directories in a commit (the complete snapshot), use 'git ls-tree [commit_id]'. Git stores files as 'blobs' and directories as 'trees', and 'git show [object_id]' can display the content of these objects.
If staged changes are not ready for commit, they can be unstaged. Using 'git restore --staged [filename]' (available in Git 2.28+), moves changes from the staging area back to the working directory. 'git restore --staged .' unstages all files. When restoring a new file that doesn't exist in the last commit, 'git restore --staged' will move it back to an untracked state.
To discard local changes in the working directory that are not staged, use 'git restore [filename]' or 'git restore .' to discard all. This reverts the file to its state in the staging area (or the last commit if not staged). To remove new, untracked files, use 'git clean -fd'. The '-f' (force) flag is required as this is a destructive operation. The '-d' flag also removes untracked directories.
To restore a file to a previous version, such as after accidentally deleting it and committing the deletion, use 'git restore --source [commit_id] [filename]'. For example, 'git restore --source HEAD~1 file1.js' restores 'file1.js' from the commit before the last one. The restored file will appear as a new untracked file in the working directory, and can then be re-added and committed if desired.