Your essential guide to Git commands, core concepts, and popular workflows.
Set your user identity for all local repositories. Typically done once per machine.
git config --global user.name "Your Name"git config --global user.email "you@example.com"git config --global init.defaultBranch maingit config --global core.editor "code --wait" (Example for VS Code)git config --listStart a new project with Git or obtain a copy of an existing one.
Navigate to your project directory, then run: git init
git clone <repository_url>
Example: git clone https://github.com/example/project.git
This creates a local copy named after the project.
Understand Git's core areas: Working Directory, Staging Area (Index), and the Repository itself.
Your project files
Changes for next commit
Committed history
git add to stage.git commit to save staged changes here.Want the mechanics behind these three areas โ what the index actually is on disk, why commits are full snapshots rather than diffs? See Git Internals: the big idea.
Specify intentionally untracked files or directories that Git should ignore (e.g., build artifacts, log files, environment variables).
Create a file named .gitignore in your project's root directory.
Each line in .gitignore specifies a pattern:
# are treated as comments.*.log, node_modules/, build/)./ matches files only in the root directory./ specifies a directory.! to negate a pattern (un-ignore) if a parent folder is ignored..gitignore:# Comments start with a hash
# Ignore compiled Python files
*.pyc
__pycache__/
# Ignore dependency directories
node_modules/
vendor/
# Ignore sensitive files
.env
*.secret
# Ignore OS-generated files
.DS_Store
Thumbs.db
It's crucial to commit your .gitignore file to the repository so it's shared with collaborators.
.gitignore only affects untracked files โ it will not stop already-tracked files from being committed. Untrack them first with git rm --cached <file>; see this misconception explained.
For common templates, check GitHub's .gitignore collection.
The fundamental workflow: check status, stage changes, and commit them to history.
git status (shows current state of working directory and staging area)
git add <filename>git add <file1> <file2>git add .git add -Agit add -p (Patch mode)git commit -m "Your descriptive commit message"git commitgit commit -a -m "Message" (Does NOT add new untracked files)git commit --amend (Opens editor for message, adds currently staged changes) Rewrites history!What add and commit actually do to the object database and refs: see porcelain โ plumbing in Git Internals.
Inspect past commits and see differences between states.
git loggit log --onelinegit log --graph --decorate --oneline --allgit log -n 5 (shows last 5)git log -pgit diffgit diff --staged (or --cached)git diff HEADgit diff <commit1> <commit2>git diff <branch1>..<branch2>Manage files within Git's tracking system.
git rm <filename>git rm --cached <filename>git mv <old-name> <new-name>
Equivalent to manually renaming, then git rm <old-name> and git add <new-name>.
Isolate development work using branches. Create, list, switch, and delete them.
Branches are lightweight movable pointers to commits, allowing parallel lines of development. Literally: a branch is a 41-byte file containing a commit SHA โ see how refs actually work.
git branch (* indicates current branch)git branch <branch-name>git switch <branch-name> (Modern Git)
git checkout <branch-name>)
git switch -c <branch-name> (Modern Git)
git checkout -b <branch-name>)
git branch -d <branch-name>git branch -D <branch-name> Use with caution!git branch -m <new-name>A basic illustration of creating and merging a feature branch.
Combine work from different branches using merge (preserves history) or rebase (linearizes history).
To merge feature-branch into your current branch (e.g., main):
git switch maingit merge feature-branchMay result in a "merge commit" if histories diverged โ Git finds the merge base and does a three-way merge.
If Git reports conflicts:
<<<<<<<, =======, >>>>>>>).git add <resolved-file>git commitgit merge --abort (before committing).
To rebase feature branch onto main (reapplies feature commits on top of main's tip):
main is up-to-date: git switch main; git pull (if remote)git switch featuregit rebase mainWarning: Do NOT rebase commits that have already been pushed to a shared remote repository and are used by others. It rewrites history and can cause severe problems for collaborators. See why rebase changes every downstream hash for the mechanics behind this warning.
Conflicts during rebase: Resolve, git add <file>, then git rebase --continue. Abort: git rebase --abort.
Gitflow is a structured branching model designed for projects with scheduled releases. It defines specific roles for different branches. Click branch names below for details.
Purpose: Stores the official release history. Code on main should always be stable and deployable. Each commit on main is a tagged release (e.g., v1.0, v1.0.1).
Derives from: Initial commit.
Merges into: Nothing (but receives merges from release and hotfix branches).
Purpose: Serves as an integration branch for features. Contains the latest development changes for the next release. This branch can be unstable at times.
Derives from: main.
Merges into: Nothing directly (but feature branches merge into it, and release branches are created from it).
feature/user-auth)Purpose: Used to develop new features. Each feature gets its own branch to isolate work.
Derives from: develop.
Merges into: develop (once the feature is complete and reviewed).
Naming: Typically feature/* or feat/*. Should not interact directly with main.
release/v1.1.0)Purpose: Prepare for a new production release. Allows for final bug fixes, documentation generation, and other release-oriented tasks. No new major features are added here.
Derives from: develop (when develop is deemed feature-complete for the release).
Merges into: main (tagged with release version) AND back into develop (to ensure fixes are in future development).
hotfix/critical-login-bug)Purpose: Address urgent critical bugs in a production release quickly. Allows patching without disrupting ongoing development on develop.
Derives from: main (from the specific tagged version that has the bug).
Merges into: main (tagged with a new patch version) AND back into develop (to ensure the fix is also in subsequent development).
Gitflow is one of many branching strategies. Others include GitHub Flow (simpler, for continuous deployment) and GitLab Flow.
Connect your local repository to remote ones (e.g., on GitHub, GitLab, Bitbucket).
git remote -vgit remote add <name> <url> (Common name: origin)git remote show <name>git remote set-url <name> <new-url>git remote rename <old-name> <new-name>git remote remove <name>Download changes from a remote repository to your local one.
git fetch <remote-name> (e.g., git fetch origin)
Downloads commits, files, and refs from the remote into your local repository. Updates remote-tracking branches (e.g., origin/main). Does NOT automatically merge these changes into your local working branches.
After fetching, you can inspect changes (e.g., git log origin/main..main) or merge manually (git merge origin/main).
git pull <remote-name> <branch-name> (e.g., git pull origin main)
Effectively runs git fetch followed by git merge <remote-name>/<branch-name> into your current local branch. If your local branch tracks a remote branch, a simple git pull often suffices.
Upload your local commits to a remote repository to share them.
git push <remote-name> <branch-name> (e.g., git push origin main)
Transfers commits from your local branch to the specified branch on the remote.
The first time you push a new local branch, you may need to set its upstream counterpart on the remote:
git push -u <remote-name> <local-branch-name>
This sets <remote-name>/<local-branch-name> as the upstream. Subsequent pushes from this local branch can use a simple git push.
Force Push: git push --force <remote> <branch> (or -f). Overwrites the remote branch. Can discard history and cause problems for collaborators. Use with extreme caution and only if you know what you're doing (e.g., on a personal feature branch you haven't shared).
Understand and manage references to branches on your remotes.
Remote-tracking branches are local read-only references to the state of branches on your remote repositories (e.g., origin/main, origin/feature-x). You don't work on them directly.
git branch -rgit branch -agit switch -c <local-branch> <remote>/<remote-branch>
git switch -c my-feature origin/feature-abc)
feature-abc only exists on one remote, git switch feature-abc will automatically set up tracking.
git push <remote-name> --delete <branch-name>
git push origin --delete old-feature)
Create permanent markers for specific commits, typically used for software releases (e.g., v1.0, v2.1.3).
git taggit tag <tag-name>git tag -a <tag-name> -m "Tag message for version X.Y.Z"git tag -a <tag-name> <commit-hash> -m "Message"git push <remote-name> <tag-name> (e.g. git push origin v1.0)git push <remote-name> --tagsgit tag -d <tag-name>git push <remote-name> --delete <tag-name>Temporarily save uncommitted changes (stash) or remove untracked files from your working directory (clean).
Useful when you need to switch branches but have uncommitted work.
git stash or git stash push -m "Optional message"git stash -u (or --include-untracked)git stash listgit stash popgit stash applygit stash apply stash@{N} (N is stash index)git stash dropgit stash clear Irreversible!Warning: git clean permanently deletes files from your working directory. Use with extreme caution.
git clean -n (or --dry-run)git clean -f (--force)git clean -fdgit clean -iPowerful commands to undo changes at different levels. Understand their impact before use.
git reset (Moves HEAD, affects Index/Working Dir based on mode):Primarily used to unstage changes or revert commits on a local branch before pushing.
git reset --soft <commit>: Moves HEAD to <commit>. Staging area and working directory are NOT changed. Commits after <commit> become staged changes. Useful for redoing a series of commits.git reset --mixed <commit> (Default mode): Moves HEAD to <commit>. Staging area is updated to match <commit>. Working directory is NOT changed. Changes are now unstaged. Example: git reset HEAD~1 (uncommits last commit, changes are unstaged).git reset --hard <commit>: Moves HEAD to <commit>. Staging area AND working directory are forcefully updated to match <commit>.
Warning: Discards ALL uncommitted changes in staging and working directory since <commit>. Potentially destructive and can lead to data loss if not used carefully. (The commits themselves usually aren't gone instantly โ see reflog recovery.)For exactly what each mode moves at the ref/index/working-dir level, see the git reset mode table in Git Internals.
git restore (Restores files in Working Dir or Staging Area):A safer, more focused command for discarding changes.
git restore <filename>git restore --staged <filename>git restore --source=<commit> --staged --worktree <filename>Various ways to specify particular commits in Git commands (log, diff, reset, etc.).
1a410efbd13591db07496601ebc7a059dd55cfe9)1a410e - usually first 7 chars are enough)main, feature/login - points to the tip of the branch)v1.0.0 - points to the tagged commit)HEAD: Points to the currently checked-out commit (tip of current branch).HEAD~1 or HEAD^: The first parent of HEAD.HEAD~N: The Nth grandparent of HEAD (following first parents).HEAD^N: The Nth parent of HEAD (useful for merge commits with multiple parents).<branch>@{yesterday} or <branch>@{"2 hours ago"}: Commit on a branch at a specific time.<branch>@{N}: Nth prior position of the branch reference (uses the reflog).:/<text>: Newest commit whose message contains <text>.Why ~ and ^ behave differently: see ancestry shorthand in the commit DAG.