Git Flashcards

(112 cards)

1
Q

version control system (VCS)

A

Git is the distributed version control system (VCS). Nearly every developer in the world uses it to manage their code. It has quite a monopoly on VCS. Developers use Git to:

Keep a history of their code changes
Revert mistakes made in their code
Collaborate with other developers
Make backups of their code
And much more

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
2
Q

command syntax

A

command <required> [optional]</required>

Arguments in angle brackets <> are mandatory and must be provided when running the command.
Arguments in square brackets are optional and can be included if needed.

Example: Create a new directory in your terminal
mkdir <directory-name></directory-name>

*<directory-name> is a required argument.</directory-name>

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
3
Q

RTFM

A

Read the Fucking Manual

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
4
Q

Porcelain Commands

A

High-Level commands. These are the ones you’ll use the most often as a developer to interact with your code.

Examples of commonly used porcelain commands:
git status
git add
git commit
git push
git pull
git log

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
5
Q

Plumbing Commands

A

Low-Level commands. (Using these will explain how Fit really works; you won’t use these often as a dev)

Examples:
git apply
git commit-tree
git hash-object

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
6
Q

Porcelain vs Plumbing Commands

A

In Git, commands are divided into high-level (“porcelain”) commands and low-level (“plumbing”) commands. The porcelain commands are the ones that you will use most often as a developer to interact with your code. Some porcelain commands are:

git status
git add
git commit
git push
git pull
git log
Don’t worry about what they do yet, we’ll cover them in detail soon. Some examples of plumbing commands are:

git apply
git commit-tree
git hash-object

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
7
Q

Git comes with a configuration both at the global and the repo (project) level. Most of the time you’ll just use the ___

A

global config

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
8
Q
A
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
9
Q

A file can be in one of several states in a Git repository. A few important ones include:

A

untracked: Not being tracked by Git
staged: Marked for inclusion in the next commit
committed: Saved to the repository’s history

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
10
Q

What does it mean s when a file is untracked, staged, or committed?

A

untracked: Not being tracked by Git
staged: Marked for inclusion in the next commit
committed: Saved to the repository’s history

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
11
Q

.md

A

markdown file extension

Markdown is a lightweight markup language that you can use to add formatting elements to plaintext text documents.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
12
Q

How can you tell the status of a file (i.e., determine whether it is untracked, staged, or committed?)

A

git status

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
13
Q

How do you stage a file?

A

If already in the right directory:

git add

Example:
file: contents.md

git add contents.md

If not in the right directory
#git add <path><filename>
git add /app/main.py</filename></path>

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
14
Q

How do you commit a file?

A

After staging a file: git add <path-to-file | pattern>
you can commit it: git commit -m “your message here”

Example:
If already in the right directory:

git add contents.md
git commit -m “add contents.md”

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
15
Q

How do you see recent commits?

What does this do?

A

git log

It opens in a pager, so you can:
-scroll up and down with arrow keys
-page down with space
-search with /
-quit with q

Note:
-your terminal locks
-you can’t type normal commands
-you have to press q to get back.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
16
Q

How do you see recent commits NOT in a scrollable viewer and only view the last 5 commits

A

git –no-pager log -n 5

As opposed to git log, git -no-pager log -n 5 only shows the last 5 commits, and prints them directly (no pager)

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
17
Q

What are commit hashes derived from?

What else affects the end hash?

A

commit hashes are derived from their content changes (i.e., the content committed to the repo).

Other stuff that affects the end hash:
-the commit message
-the author’s name and email
-the date and time
-parent (previous) commit hashes

Note: A full git hash is a 40-character hexadecimal number

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
18
Q

SHAs

A

Occasionally you may hear commit hashes referred to as “SHAs”

Why? Git uses a cryptographic hash function called SHA-1 to generate commit hashes

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
19
Q

What’s the start hash? What’s the end hash?

A

When you specify a range of commits, Git needs:
-a start hash
-an end hash

Example:
git log abc123..def456

This means:

“Show commits after abc123 up to and including def456”

So:
abc123 → start (exclusive)
def456 → end (inclusive)

The “end hash” is just:
👉 the commit where you want Git to stop

“end hash” can also mean the most recent commit

Rule of thumb: If you hear “end hash”, mentally translate it to:
“The commit hash that represents where we want to stop.”

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
20
Q

Hexadecimal

A

Base-16 number system
It uses 16 unique digits: 0 through 9 and A through F

It is widely used in computer science, because it provides a more compact, human-readable representation of binary data (base-2) as each hex digit represents exactly 4 bits.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
21
Q

How do you see the contents of a commit without futzing around with the object files directly?

A

git cat-file -p <hash></hash>

Example:
git cat-file -p 5b21d4f16a4b07a6cde5a3242187f6a5a68b060f

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
22
Q

How do you redirect the output (i.e., the output of the contents of a commit) to a temp file?

A

catfile-command-here > /tmp/catfileout.txt

Example:
git cat-file -p 5b21d4f16a4b07a6cde5a3242187f6a5a68b060f >/tmp/catfileout.txt

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
23
Q

grep

A

global regular expression print

grep searches for patterns and prints the lines that match

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
24
Q

tree

A

Git’s way of storing a directory

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
25
blob
git's way of storing a file
26
Git stores an entire snapshot of files on a per-commit level. What does this mean?
What “per-commit level” means (plain English) “Per-commit level” means: for each commit, Git records the state of the entire project as it looked at that moment. So instead of thinking: “A commit = just the diff from the previous commit” Git’s model is: “A commit = a snapshot of the whole project at that point in time.” Every commit corresponds to a complete project state. What Git is not doing Git is not saying: “This commit stores only the lines you changed” “This commit only contains deltas” “Files not changed don’t exist in this commit” That is how some older version control systems worked — but not Git. How this works without wasting huge amounts of space Here’s the key part that usually clicks next: Git conceptually stores a full snapshot, but physically deduplicates unchanged content. Under the hood: Each file’s contents are stored as a blob object Each directory is stored as a tree object A commit points to one tree If a file didn’t change: The commit just re-uses the same blob hash No extra storage is used So you get: Snapshot semantics Delta-like efficiency Best of both worlds. Concrete example Imagine a repo with two files: README.md app.py Commit 1 README.md → "Hello" app.py → "print('v1')" Git stores: Blob A (README) Blob B (app.py) Tree T1 Commit C1 → T1 Commit 2 (only app.py changes) README.md → "Hello" app.py → "print('v2')" Git stores: Blob C (new app.py) Reuses Blob A (README unchanged) Tree T2 Commit C2 → T2 👉 Even though only one file changed, Commit 2 still represents the entire project state. That’s what “per-commit level” means.
27
Git Optimization, describe
Optimization While it's true that Git stores entire snapshots, it does have some performance optimizations so that your .git directory doesn't get too unbearably large. Git compresses and packs files to store them more efficiently. Git deduplicates files that are the same across different commits. If a file doesn't change between commits, Git will only store it once.
28
What command do you use to find the absolute path of the top-level directory of a repository?
git rev-parse --show-toplevel
29
cat .git/config vs. git config list --local
cat shows what’s written. git config shows what Git believes. cat .git/config Shows the raw file contents. Exactly what’s stored on disk. No interpretation, no merging, no filtering. Think of this as: “Open the hood and look directly at the wiring.” Example output: [core] repositoryformatversion = 0 filemode = true [remote "origin"] url = git@github.com:user/repo.git git config --list --local Uses Git’s config system. Reads .git/config. Parses it. Normalizes formatting. Outputs key=value pairs Think of this as: “Ask Git to explain what it understands the config to be.” Example output: core.repositoryformatversion=0 core.filemode=true remote.origin.url=git@github.com:user/repo.git Rule of Thumb: If you’re learning: use both. If you’re working or scripting: always use git config.
30
Explain what each section of the following commands do: git config set --global user.name "ThePrimeagen" git config set --global user.email "the.primeagen@aol.com"
git config: The command to interact with your Git configuration. set: The subcommand to set a value – i.e., to add it if it doesn't already exist, or update it if it does. --global: Flag stating you want this configuration to be stored globally in your ~/.gitconfig. The opposite is --local, which stores the configuration in the current repository only. user: The section. name: The key within the section. "ThePrimeagen": The value you want to set for the key.
31
How do you get a single value?
git config get Keys are in the format
.. For example: user.name webflyx.ceo NOTE: You do not need to know the value ahead of time; you only need to know (or guess) the key name. You use git config get precisely when you’re not sure: -whether it’s set at all, -what its current value is, -or at which level it’s set. Example 1: “Why is Git using the wrong name/email?” You commit and see: git log -1 Output shows: Author: Old Name You thought you fixed this already. Time to check config: git config get user.name # what name is Git using here? git config get user.email # what email? Possible outcomes: It prints a value → “Ah, that’s still my old email; need to change it.” It errors / prints nothing → “Okay, maybe it’s not set at this level.” Then you can check higher levels: git config get --global user.email git config get --system user.email Now you’re using get to discover: -Is the key set? -If so, to what? -At which level? -You didn’t know the value ahead of time; you just knew the key name (user.email), which is part of Git’s public config API.
32
How do you remove a configuration value?
Use the unset subcommand. git config unset
33
Can you have duplicate keys in key/value stores in python? What about in git?
python: no git: yes
34
How do you purge all instances of a key from a configuration?
git config unset --all example.key Example: remove all instances of ceo from the webflyx section: git config unset --all user.webflyx.ceo
35
How do you remove a section?
git config remove-section
Example: Remove the webflyx section: git config remove-section webflyx
36
~ means what?
Start at my home directory. Example: If you see ~/.gitconfig the shell actually turns it into something like: /home/kasey/.gitconfig
37
What do the following mean at the start of a file path? / (tilda symbol)/ Git-specific: my-repo/ .git
Here are the important “roots”: Thing What it means / Filesystem root (indicates that it's an absolute path) (tilda symbol) User home directory (this expands to an absolute path; it's expanded by the shell, so when git runs it, it's an absolute path.) my-repo/ Repo root (relative path. There is a directory called my-repo under my current working directory. .git/ Git’s internal directory (from the shell's perspective: relative; from Git's perspective: relative to the repo root)
38
What's a good rule of thumb when evaluating whether a path is relative or absolute?
If a path starts with /, it is absolute. If it starts with ~, it becomes absolute. Everything else is relative — but the reference point depends on who is interpreting it (shell vs Git).
39
Git configurations from specific to general
worktree>local>global>system Note: If you set a configuration in a more specific location, it will override the same configuration in a more general location. So, worktree(overrides local)> local(overrides global)> global(overrides system)> system What happens when you work in each of these locations? worktree: For this specific working directory, what should Git do? local: How should Git behave for this project, regardless of who's using it or where it's checked out? global: How do I like Git to behave everywhere I use it? system: What rules apply to everyone on this system?
40
What are the differences between the following locations where Git can be configured? worktree local global system
worktree: For this specific working directory, what should Git do? local: How should Git behave for this project, regardless of who's using it or where it's checked out? global: How do I like Git to behave everywhere I use it? system: What rules apply to everyone on this system?
41
What does it mean to "configure Git"
It means to tell Git how you want it to behave. Note: That is, how git SHOULD MAKE DECISIONS when you run commands. What kinds of decisions does Git need to make? Git constantly has to answer questions like: -Who is making this commit? -Which editor should I open? -How should I combine histories? -How should line endings be handled? -How should files be ignored? -How should I talk to the network? -How strict should security be? If you don’t answer, Git: -Uses defaults -Or guesses -Or stops and asks you (sometimes badly) Configuring Git = pre-answering those questions.
42
Where are the following locations stored in Git? System, Global, Local, Worktree
system: /etc/gitconfig (system-wide, not in a user's home directory) global: ~/.gitconfig (stored in the user's home directory) local: .git/config (stored in a specific project's .git folder) worktree: .git/config.worktree (also stored in a project's .git folder)
43
What does a git branch let you do?
keep track of different changes separately. Example: let's say you have a big web project and you want to experiment with changing the color scheme. Instead of changing the entire project directly (as of right now, our master branch), you can create a new branch called color_scheme and work on that branch. When you're done, if you like the changes, you can merge the color_scheme branch back into the master branch to keep the changes. If you don't like the changes, you can simply delete the color_scheme branch and go back to the master branch.
44
What's a commit?
A snapshot of "save point" of your project's entire file system at a specific point in time.
45
master vs main
GitHub recently changed its default branch from master to main. Good rule of thumb: use main as your default branch if you work primarily with GitHub
46
What is init.defaultBranch ?
init.defaultBranch is a Git configuration key that tells Git: “When I run git init to create a new repository, what should the first branch be called?” By default in older setups it was master. When you set: git config set --global init.defaultBranch main you’re saying: “For all new repos I create on this machine, name the initial branch main instead of master.” It does not rename existing branches; it only affects repositories you create after setting it.
47
Code Review
Code Review: Before any code from a feature branch (like lanes_branch) is merged into a main development branch (like main), it almost always goes through a code review process. This means other developers examine the code for quality, bugs, adherence to standards, and potential issues, including how it might interact with existing code.
48
Protected Branches
Protected Branches: Version control platforms (like GitHub, GitLab, Bitbucket, etc.) allow administrators to set up protected branches. For a protected branch, you can enforce rules such as: Require pull requests: No direct pushes are allowed; all changes must come through a pull request (or merge request). Require successful status checks: Automated tests, linters, and other checks must pass before a merge. Require approvals: A certain number of code reviews must be approved by designated team members. Restrict who can merge: Only specific users or teams can actually click the "merge" button.
49
CI/CD Pipelines:
Continuous Integration/Continuous Deployment (CI/CD) pipelines often run automatically when a pull request is created or updated. These pipelines can run tests, build the application, and even deploy to staging environments. If any step fails, the merge is typically blocked.
50
Ownership and Responsibility:
Teams often have clear ownership for different parts of a codebase. If a merge conflict arises in a specific area, the developer responsible for that area might be best suited to resolve it, or at least approve the resolution.
51
Organizational practices around merge in Git
So, while Git can just let you merge, the organizational practices around it often add layers of approval and automated checks to ensure code quality and prevent unintended issues, especially when dealing with potential conflicts.
52
Two ways to create a new branch
This creates a new branch called my_new_branch git branch my_new_branch This creates a new branch called my_new_branch and switches to it immediately. git switch -c my_new_branch Example: Create and switch over to a branch called add_classics Step 1: confirm that you're on the main branch git branch output: main step 2: create and switch over to add_classics git switch -c add_classics
53
git switch is the newer way to change branches. What's the older way?
git checkout Example: switch to a branch called prime #new way: git switch prime old way: git checkout prime
54
Explain the difference between: git log --decorate=short git log --decorate=full git log --decorate-no
--decorate is a flag that can make the output easier to read --decorate=short (the default) This shows branch and tag names in a shortened format. For example: commit abc123 (HEAD -> main, origin/main) The branch names are shown without their full path prefix. --decorate=full This shows the complete reference path. For example: commit abc123 (HEAD -> refs/heads/main, refs/remotes/origin/main) Notice how it shows refs/heads/main instead of just main, and refs/remotes/origin/main instead of origin/main. This reveals the full internal structure of how Git stores references. --decorate=no This removes all decoration entirely: commit abc123 No branch names, no tags, no HEAD indicator - just the commit hash and message. Here's the full path: .git/ ├── refs/ │ ├── heads/ # Local branches │ │ ├── main │ │ └── add_classics │ ├── remotes/ # Remote tracking branches │ │ └── origin/ │ │ └── main │ └── tags/ # Tags │ └── v1.0
55
What are flags?
Flags are extra options you add to a command to customize: -what it shows (e.g., include or hide author/date) -how it shows it (e.g., compact vs detailed, colors, decorations, etc.) Example: --decorate=full or --decorate=no or --decorate=short are all flags that can make the output easier to read
56
How to exit editors: -Nano -Vim -VSCode
If Nano was opened, press ctrl+x, then y to confirm, and Enter to save. If Vim was opened, press esc, then : to enter command mode, then wq to write and quit. If VSCode was opened, press ctrl+s or cmd+s to save, then click the x button to close.
57
If you mess up a commit message, how do you change it?
Use the --amend flag Example: git commit --amend -m "F: Merge branch 'add_classics'"
58
How do you see a ASCII art representation of your commit history?
git log --oneline --graph --all
59
How do you merge a branch onto the main branch?
git switch main #must be on the branch you're merging another branch onto; in this case, main. git merge name_of_branch_to_be_merged
60
What does --oneline do?
Gives you a condensed view of your history. Hash are shortened to 7 characters. You get the commit message so you can see what happened in the past
61
What does --graph do?
Visual graph (little lines) to show how your commits have diverged and come back together
62
What does --decorate do?
It gives you the branch and tag info. This can be nice to see how far away you've strayed away from a branch or where a previous branch may be. Example: (HEAD, main) (feature) (tag: v0.9) in the below output: 0e25143 (HEAD, main) Merge branch 'feature' ad8621a (feature) Fix a bug in the feature 16b36c6 Add a new feature 23ad9ad (tag: v0.9) Add the initial code base
63
--parents
parents will give you the parent commit upon every other commit This can be nice for merge commits because you can see where the two parents came from to create the merge commit
64
What's the common workflow when working with a team of devs?
# delete the add_classics branch It's a common workflow when working with Git on a team of devs: 1. Create a branch for a new change 2. Make the change 3. Merge the branch back into main (or whatever branch your team dubs the "default" branch) 4. Remove the branch 5. Repeat Example: git branch -d add_classics # 1. create a new branch off main called update_titles git switch -c update_titles # 2. update titles.md by adding a final entry to the list of movies (nvim edit, etc.) # 3. and then commit the update to that branch git commit -m "add titles.md" # Confirm the commit is there git log --oneline
65
How do you delete a branch?
Example: delete the update_titles branch git branch -d update_titles
66
What's a fast-forward merge
Example: Suppose you have a main branch and a feature branch. You start by creating a new branch feature from the main. A----B----C (main) \ D----E (feature) If no new commits are added back to the main branch while you work on a feature, the history remains linear. When you merge the feature back into the main, Git doesn't have to create a new merge commit. Instead, it simply moves the pointer of the main branch to the latest commit in the feature. A----B----C----D----E (main, feature) This is a fast-forward merge because no additional commits are needed to integrate the changes. When does Git use fast-forward merges? 1) The target branch has not diverged from the branch being merged Example: A----B----C----D----E (feature) ^ main In this instance, main is behind. It has not diverged. It is pointing at an earlier commit in the same line. 2) The branch being merged is directly ahead of the target branch. Example: A----B----C----D----E (feature) ^ main Every commit on feature comes after main. No sideways history. No alternative path. Git can say: feature is just a later version of main SO it simply moves main forward: A----B----C----D----E ^ main, feature 3) The commit history is linear with no conflicting changes. Example: A----B----C----D---E So there is only one path from start to finish. (As opposed to a non-linear history: A----B-----C \ D----E in which Git would have to compare two paths, potentially resolve conflicts, and create a merge commit. As opposed to linear history, where there is only one timeline and nothing to reconcile. Mental Shortcut: Can I draw a straight line from main to feature (new branch) without turning? Yes: fast-forward merge No: real merge commit needed
67
How do you confirm that a commit processed/is there?
git log --oneline
68
Rebase vs Merge
Rebase A - B - C (main) \ D - E (feature_branch) Rebase: A - B - C (main) \ D - E (feature branch) vs Merge A - B - C (main) \ D - E (feature_branch) Merge: A - B - C - F (main) \ / D - E (feature_branch) Merge creates an additional merge commit. Rebase does not. Pros & Cons to Merge: -Pro: It preserves the true history of a project. It shows when branches were merged and where. -Con: It can create a lot of merge commits, which can make the history harder to read and understand
69
Pros & Cons to a Merge vs Rebase
Pros & Cons to Merge: -Pro: It preserves the true history of a project. It shows when branches were merged and where. -Con: It can create a lot of merge commits, which can make the history harder to read and understand vs Rebase, which does not create an additional merge commit.
70
Syntax for Rebase
The branch you check out is the one that gets rebased (i.e., it moves) The branch you name in the command is the base (i.e., it stays still) So: git checkout my_feature git rebase main means: Move my_feature so that it's based on top of main *This is safe if my-feature is your private branch
71
What should you NEVER do with rebase
NEVER rebase (move) a public branch (like main) onto anything else. Other devs have it checked out, and if you change its history, you'll cause a lot of problems for them. So, this is okay: git checkout my_feature git rebase main means: Move my_feature so that it's based on top of main *This is safe if my-feature is your private branch BUT this is NOT okay: git checkout main #dangerous: you are now on the public branch git rebase some_other_branch means: move main so that it's based on top of some_other_branch This means that main is the one being written which is NOT okay. Safety Check: Before running rebase, ALWAYS check: git status & confirm that you're on a PRIVATE branch (e.g., feature_x and NOT main/master/dev) Then run: git rebase main or whatever public branch you want to rebase onto.
72
What do you do if you rewrite the main branch (rebase it), which you should NEVER do?
Step 1: Find the old main tip: git checkout main git reflog Look for the commit right before the bad rebase. It'll say something like: HEAD@{2}: update by puch or HEAD@{n}: checkout: moving from something to main Copy the Step 1.5: Tag it for safety (optional) Tag the current (bad) state just in case: git tag back-up-bad-main git push origin back-up-main Step 2: Reset local main back to it git reset --hard Step 3: Force-push the fix git push --force origin main Step 4: Tell the team: -what happened -That main was briefly rewritten but has been restored -That if anyone did work on top of the temporary bad main, they may need help rebasing or using git reflog to recover.
73
git reset --soft
This command can be used to undo the last commit(s), any changes in the index (staged but not committed changes), and the worktree (unstaged and not commited changes). git reset --soft COMMITHASH COMMITHASH *you can find this by going to git log --oneline. Copy the commit hash and insert --soft is useful if you want to go back to a previous commit but keep all of your changes. That is, committed changes will be uncommitted and staged, while uncommitted changes will remain staged or unstaged as before
74
What does the "index" reference?
staged but not committed So, for example, if you reset any changes in the index, you would be undoing the staged but not committed changes
75
What does the "worktree" reference?
unstaged and not committed changes So, for example, if you reset the worktree, you would be undoing any unstaged and not committed changes
76
git reset --hard WARNING
git reset --hard COMMITHASH Get the hash by: git log --oneline (then copy the commit hash you want to undo) The --hard flag makes your working directory and staging area match the specified commit exactly, discarding any local changes. The -soft flag will keep changes (i.e., committed changes will be uncommitted and staged and uncommitted changes will remain staged or unstaged as before). Versus the -hard flag which discards all changes fully. WARNING: git reset --hard is a dangerous command. If you use it to undo commiting a file, it's gone for good.
77
Reset to a Specific Commit
WARNING: git reset --hard is a dangerous command. If you use it to undo commiting a file, it's gone for good. git reset --hard COMMITHASH This will reset your working directory and index to the state of that commit, and all changes made after that commit are lost forever. NOTE: COMMITHASH *you can find this by going to git log --oneline. Copy the commit hash and insert
78
Branch
A movable pointer to a commit (like main, feature/login)
79
Commit Graph
Git stores commits as a graph where each commit points to one (or more) parents
80
Fast-Forward Merge
When the target branch can just "move forward" to the other branch's tip because there are no divergent commits
81
Merge Commit
A commit with two parents that explicitly joins two lines of development
82
Fast-Forward Merge vs Merge Commit
When the target branch can just "move forward" to the other branch's tip because there are no divergent commits vs A commit with two parents that explicitly joins two lines of development
83
Git repository/Git repo/repo
A Git repository, often called a "repo," is a central place where the history of a project is stored, tracked, and managed. It includes all the files and directories necessary for a project, along with a hidden .git directory that contains all the versioning information managed by Git. Each project typically has its own repository.
84
How do you start a new project with Git?
initialize a new repository within your project directory using git init Example: Initialize a New Git Repository: mkdir cd git init
85
remotes
Often our frenemies (read: coworkers) make code changes that we need to begrudgingly accept into our pristine bug-free repos. /s This is where the "distributed" in "distributed version control system" comes from. We can have "remotes," which are just external repos with mostly the same Git history as our local repo. In git, another repo is called a "remote."
86
What do you name "origin"
The standard convention is that when you're treating the remote as the "authoritative source of truth" (such as GitHub) you would name it the "origin". By "authoritative source of truth" we mean that it's the one you and your team treat as the "true" repo. It's the one that contains the most up-to-date version of the accepted code. Note: When it comes to Git (the CLI tool), there really isn't a "central" repo. GitHub is just someone else's repo. Only by convention and convenience have we, as developers, started to use GitHub as a "source of truth" for our code.
87
What does git remote -v do?
It tells you where Git is trying to look. If an "address" (URL/file or directory location) is wrong, git remote set-url is your tool to fix it. git remote set-url origin
88
What happens when you rebase a public branch?
Rebasing a public branch is a bit like a wizard trying to rewrite history after the townspeople have already read the history books. When you rebase, you are creating entirely new commits for your changes. If you do this on a branch that others have already downloaded (pulled) to their own machines, their history will no longer match yours. This often leads to significant confusion and "merge conflicts" for everyone else on the team, as Git will see two different versions of the same history. In a shared environment, it is generally safer to use a "merge" commit to combine work, as it preserves the existing history rather than rewriting it. Before you start worrying about complex Git maneuvers like rebasing on public branches
89
Git vs GitHub, GitLab, and Bitbucket
Git and GitHub are not the same! Git is an open-source command line tool for managing code files. GitHub and its primary competitors, GitLab and Bitbucket, are commercial web products that use Git. Their websites give us a way to store our code that's managed by Git.
90
remote/remote repo
A remote repository, or "remote repo," is a version of your project that is hosted on the internet or another network. While your local repository lives on your own machine (like your laptop), the remote repository lives on a server. Think of it like this: Local Repo: Your personal notebook where you write and edit your work. Remote Repo: A bulletin board in a library where you post a copy of your work for others to see, or as a backup so you don't lose it. Key Characteristics Collaboration: It allows multiple developers to push their changes to a central location or pull changes made by others. Hosting Services: Common places to host remote repositories include GitHub, GitLab, and Bitbucket. URLs: Every remote repo has a specific URL (like https://github.com/user/project.git) that your local Git installation uses to communicate with it. Common Interactions You interact with remote repos using specific commands: git clone: Copies a remote repo to your local machine for the first time. git push: Sends your local commits to the remote repo. git fetch: Checks the remote repo for changes without merging them into your work. git pull: Fetches changes from the remote and immediately tries to merge them into your local branch.
91
Explain the difference between a safe rebase and a destructive force push
You have the right intuition about the dangers of rewriting history, but let's sharpen the specifics of how Git handles these scenarios. The "disaster" usually stems from a force push after a rebase, rather than the rebase itself. The Standard Merge Scenario If the public branch is A-B-C-D-E and Dave has A-B-C-F locally: Dave pulls the latest changes. Dave merges his work: git merge. A new merge commit (G) is created. The history becomes A-B-C-D-E-G, where G has two parents: E and F. This is safe. No history is lost, and hashes for D and E remain unchanged. The Rebase Scenario (The “Clean” Way) If Dave rebases his private branch onto the public branch: Dave's local branch changes from A-B-C-F to A-B-C-D-E-F'. Note the F': it is a new commit with a new hash because its "parent" changed from C to E. Dave can then push this to the public branch. The history is now a straight line: A-B-C-D-E-F'. This is also safe! D and E are still there. The Disaster Scenario (Rewriting Public History) The scenario you described where D and E are "scrapped" only happens if Dave rebases the public branch itself or force pushes a branch that lacks those commits. If Dave has A-B-C-F and he does git push --force, he tells the server: "Ignore whatever you have; use my version." The server replaces A-B-C-D-E with A-B-C-F. D and E are now orphaned on the server. They aren't deleted immediately from the database, but they are no longer part of the branch history. The Consequence for Other Devs You are exactly right about the "hash mismatch." If Dave force-pushes A-B-C-F: Other developers have A-B-C-D-E in their local history. When they try to pull, Git gets confused. The "official" history no longer contains D and E. To fix this, the other developers have to "resurrect" the lost commits. They often have to use git reflog to find the hashes of D and E and then manually rebase their own work onto Dave's new (but actually older) F commit. The Golden Rule Never rebase commits that have been pushed to a public repository. If you only rebase your local, unpushed commits, you are simply cleaning up your own work before sharing it. The trouble only starts when you change the hashes of commits that other people have already built their work upon. *** The core takeaway is that Git is a history-tracking tool. As long as you are adding to the history (merging), you are safe. When you start rewriting history that others have already seen (rebasing public commits and force-pushing), you are essentially changing the past, which creates a fractured timeline for your fellow developers.
92
git push
this command pushes (sends) local changes to any "remote" Example: To push our local main branch's commits to the remote origin's main branch: git push origin main Note: You need to be authenticated with the remote to push changes. Example 2: You can also push to a local branch to a remote with a different name: git push origin :
93
I can't escape an editor
Step 1: Determine what editor you're in. If you see ^X you're in Nano editor. If Nano was opened, press ctrl+x, then y to confirm, and Enter to save. Otherwise, you may be in Vim To save and exit: Press Esc (to make sure you're in command mode) Type :wq (colon, then w, then q) Press Enter
94
pull
To get actual file changes from a remote repo (i.e., you're pulling a change from the remote repo down to the local repo.) command syntax: git pull [/] The [...] syntax means that the bracketed remote and branch are optional. If you execute git pull without anything specified it will pull your current branch from the remote repo.
95
I tried to push or pull to a remote branch and got an error message about an invalid username or token. What do I do?
1) Confirm you’re pushing over HTTPS (token is for HTTPS) Run: git remote -v If you see https://github.com/..., token auth applies. If you see git@github.com:..., that’s SSH (token won’t help). In that case either set up SSH keys, or switch the remote to HTTPS. To switch to HTTPS: git remote set-url origin https://github.com//.git 2) Clear the saved bad GitHub credential (most common fix) If an old password/token is cached, Git will keep reusing it and you’ll get “invalid username or token”. macOS Open Keychain Access → search “github.com” → delete the “internet password” entries for github. Windows Credential Manager → Windows Credentials → remove entries for github.com. Linux If you’re using the credential helper, often: git credential reject Then paste this when prompted: protocol=https host=github.com (Or remove the github entry from your credential manager if you have one.) Then try pushing again; Git should prompt you: Username: your GitHub username Password: paste the token (PAT) 3) Make sure the token is valid and not expired/revoked On GitHub → Settings → Developer settings → Fine-grained tokens: ensure it’s not expired ensure it’s for the correct account ensure it has access to the repo you’re pushing to (sometimes “all repos” isn’t actually selected the way you think—double-check the token’s “Repository access”) 4) If you’re using GitHub CLI, re-auth it (optional) If you use gh: gh auth status gh auth login Quick diagnostic: paste these outputs If you paste: git remote -v git status (and the exact push command you ran, plus the full error text), I can tell you which of the above is the culprit.
96
Example of a team workflow:
When you're working with a team, Git gets a bit more involved (and we'll cover more of this in part 2 of this course). Here's what I do: Update my local main branch with git pull origin main Checkout a new branch for the changes I want to make with git switch -c Make changes to files git add . git commit -m "a message describing the changes" git push origin (I push to the new branch name, not main) Open a pull request on GitHub to merge my changes into main Ask a team member to review my pull request Once approved, click the "Merge" button on GitHub to merge my changes into main Delete my feature branch, and repeat with a new branch for the next set of changes That is, while working with a team, my workflow is as follows: work on a feature branch then open a pull request for review
97
normal workflow:
git add . git commit -m "some message here" git push origin main
98
repo's root directory
This is the top-level folder of the repository—the one that contains the .git directory. From anywhere inside the repo, you can jump to the root with: cd "$(git rev-parse --show-toplevel)" To sanity-check you’re at the root, run: ls -a You should see .git/ there (and likely files like titles.md, contents.md, quotes/, etc. in this lesson’s repo). Then create your file from the root (example): touch guilty_pleasures.md
99
Why do you go to a repo's root directory?
This is the top-level folder of the repository—the one that contains the .git directory. From anywhere inside the repo, you can jump to the root with: cd "$(git rev-parse --show-toplevel)" To sanity-check you’re at the root, run: ls -a You go to the repo’s root because it’s the “single source of truth” location where tooling and teammates expect project-wide files to live, and where commands behave predictably. Benefits (and business use cases): Consistent commands: Running git add ., tests, builds, or linters from the root avoids accidentally targeting only a subfolder (common in monorepos or nested projects). Project-wide config discovery: Tools typically look upward for config files (e.g. .gitignore, package.json, pyproject.toml, go.mod, Makefile, Dockerfile, .editorconfig). Putting them at the root makes local dev and CI behave the same. Correct .gitignore scope: A root .gitignore applies to the whole repo, so you don’t accidentally track secrets/logs/build outputs from some subdirectory. Reliable paths in scripts/CI: Build pipelines often do checkout repo -> cd repo root -> run steps. Keeping scripts and paths rooted makes automation stable across machines. Clear project structure for teams: New engineers can clone the repo and immediately find docs (README.md), licensing, configs, and entry points without hunting. Security and compliance: Centralizing ignore rules and secret-handling patterns at the root reduces the chance someone commits .env, credentials, or generated artifacts. In short: working from the root reduces “it works on my machine” problems and makes automation and collaboration smoother.
100
How do you get a full path to a file or current directory or repo root?
Absolute path to the file: realpath guilty_pleasures.md Absolute path to the current directory: pwd From anywhere in the repo, you can also combine with the repo root: git rev-parse --show-toplevel
101
How do you delete an untracked file from the working tree (sometimes you don't want the working tree to be "dirty"--especially for lessons on boots as some lessons test that)
Example: A file named add_classics Delete it (only removes the untracked file): rm add_classics keep it but remove all untracked files/directories in the repo: git clean -fd
102
How do you unstage a single file?
git restore --staged
103
How do you see what's staged vs unstaged? How do you see exactly what's staged?
Verify what's staged vs unstaged: git status See exactly what's staged: git diff --staged --add_classics
104
Does .gitignore only accept exact filepath section names?
No. Wildcards The * character matches any number of characters except for a slash (/). For example, to ignore all .txt files, you could use the following pattern: *.txt This would ignore files like /princess_diaries.txt and /contacts/your_mom.txt since they're both .txt files. Rooted Patterns Patterns starting with a / are anchored to the directory containing the .gitignore file. For example, this would ignore a main.py in the root directory, but not in any subdirectories: /main.py This ignores /main.py but not /src/main.py since /src is a subdirectory. Negation You can negate a pattern by prefixing it with an exclamation mark (!). For example, to ignore all .txt files except for important.txt, you could use the following pattern: *.txt !/important.txt This would not ignore /important.txt, but would ignore /self_affirmations/important.txt. Comments You can add comments to your .gitignore file by starting a line with a #. For example: Ignore all .txt files *.txt Comments are especially helpful when doing something unconventional or complex, especially when collaborating. Order Matters The order of patterns in a .gitignore file determines their effect, and patterns can override each other. For example: temp/* !temp/instructions.md Everything in the temp/ directory would be ignored except for instructions.md. If the order were reversed, instructions.md would be ignored.
105
* & .gitignore
Wildcards The * character matches any number of characters except for a slash (/). For example, to ignore all .txt files, you could use the following pattern: *.txt This would ignore files like /princess_diaries.txt and /contacts/your_mom.txt since they're both .txt files.
106
/ & .gitignore
Rooted Patterns Patterns starting with a / are anchored to the directory containing the .gitignore file. For example, this would ignore a main.py in the root directory, but not in any subdirectories: /main.py This ignores /main.py but not /src/main.py since /src is a subdirectory.
107
! & .gitignore
Negation You can negate a pattern by prefixing it with an exclamation mark (!). For example, to ignore all .txt files except for important.txt, you could use the following pattern: *.txt !/important.txt This would not ignore /important.txt, but would ignore /self_affirmations/important.txt.
108
comments & .gitignore
Comments You can add comments to your .gitignore file by starting a line with a #. For example: Ignore all .txt files *.txt Comments are especially helpful when doing something unconventional or complex, especially when collaborating.
109
order & .gitignore
Order Matters The order of patterns in a .gitignore file determines their effect, and patterns can override each other. For example: temp/* !temp/instructions.md Everything in the temp/ directory would be ignored except for instructions.md. If the order were reversed, instructions.md would be ignored.
110
what is .gitignore?
A problem arises when we want to put files in our project's directory, but we don't want to track them with Git. A .gitignore file solves this. For example, if you work with Python, you probably want to ignore automatically generated files like .pyc and __pycache__. If you are building a server, you probably want to ignore .env files that might hold private keys. If you (I'm sorry) work with JavaScript, you might want to ignore the node_modules directory. Here's example contents of a .gitignore file, which exists at the root of a repo: node_modules .env This will ignore every path containing node_modules as a "section" (directory name or file name). It ignores: node_modules/code.js src/node_modules/code.js src/node_modules It does not ignore: src/node_modules_2/code.js env/node_modules_3 src/node_modules.js This will also ignore the .env file preventing you from committing sensitive environment variables (like API keys, DB credentials, etc.) ...cause that would be bad.
111
What should you ignore/what should you use .gitignore for?
Ignore things that can be generated (e.g. compiled code, minified files, etc.) Ignore dependencies (e.g. node_modules, venv, packages, etc.) Ignore things that are personal or specific to how you like to work (e.g. editor settings) Ignore things that are sensitive or dangerous (e.g. .env files, passwords, API keys, etc.)
112
What is a browser?
Browsers are really document viewers + network clients: they can render local files (file://), resources from servers (http://, https://), and other URI schemes.