Git
git
git is a distributed version control system. it helps you track changes to files, collaborate with others, and experiment safely without losing your work.
basic terms
| term | definition | notes / example |
|---|---|---|
| Repository (repo) | a folder that contains your project and git history | git init creates a new repo |
| Working Tree | Your actual files on disk that you edit | Files like main.py or README.md |
| Index / Staging Area | Temporary area for changes you plan to commit | git add <file> stages a file |
| HEAD | Pointer to your current commit/branch | git commit updates HEAD to the new commit |
| Branch | A movable pointer to a series of commits | main, feature-x |
| Commit | A snapshot of your project at a point in time | git commit -m "message" |
| Remote | A copy of your repository hosted elsewhere | origin is the default remote |
| Upstream Branch | Remote branch your local branch tracks | Usually origin/main |
| Merge Base | Most recent common ancestor of two branches | Used for merges |
| Conflict Markers | Sections Git inserts when a file has conflicting changes | code below |
<<<<<<< HEAD
your code
=======
their code
>>>>>>> branch
common commands
git init
- creates a new git repository in your project folder.
- adds a hidden
.gitfolder to track changes.
git status
- shows modified files, staged files, and untracked files.
- always run before committing to see the current state.
git add <file>
git add .
- adds changes to the staging area in preparation for commit.
git commit -m "Describe your changes"
- saves a snapshot of your staged changes to the repository.
- updates
HEADto point to this new commit.
git log --oneline
- Shows a concise history of commits.
- Example:
f3a2b1c Add login feature e4d5f6a Fix README typo a1b2c3d Initial commitgit branch feature-x # Create branch git checkout feature-x # Switch to branch # or combine git switch -c feature-x - branches let you experiment independently of
main.
git remote add origin <repo-url>
git push -u origin main
- sends your commits to a remote repository (like GitHub).
-usets the upstream so you can later just rungit push.
git pull
- fetches and merges changes from the upstream branch.
- ensures your branch is up-to-date with collaborators.
visualizing a simple git history
# Initial commit on main
A --- B --- C (main / HEAD)
# Create feature branch
\
D --- E (feature-x)
# Merge back to main
A --- B --- C --- F (main)
\ /
D --- E (feature-x)
- each letter represents a commit.
- branches allow parallel work.
- merge combines changes.
my usage examples
automatically git rm the deleted files
command
git ls-files --deleted | xargs git rm
explanation
to be added later
disable file mode changes from git tracking
command
git config --global core.fileMode false
explanation
to be added later
preview conflicts before merging
- the function simulates a merge without touching your files.
- conflicts are clearly highlighted in color.
- you can review which files and lines would conflict before performing an actual merge.
- it is completely safe to run on any branch with an upstream set.
command
git-conflicts-color
example output
- ted background → your local changes (HEAD)
- yellow background → separator between changes
- green background → incoming changes from upstream
underlying function
function defition
git-conflicts-color() {
# Check if inside a Git repository
git rev-parse --is-inside-work-tree >/dev/null 2>&1 || {
echo "Not inside a Git repository."
return 1
}
# Identify the upstream branch
upstream=$(git rev-parse --abbrev-ref --symbolic-full-name @{upstream} 2>/dev/null)
if [[ -z "$upstream" ]]; then
echo "No upstream branch set for this branch."
echo "Set it using: git branch -u origin/<branch>"
return 1
}
# Fetch latest remote commits
echo "Fetching latest changes..."
git fetch >/dev/null
# Show which branches are being compared
echo "Checking for merge conflicts between:"
echo " LOCAL: HEAD ($(git rev-parse --abbrev-ref HEAD))"
echo " REMOTE: $upstream"
echo
# Find the common ancestor (merge base)
base=$(git merge-base HEAD "$upstream")
# Simulate the merge in memory
output=$(git merge-tree "$base" HEAD "$upstream")
# Check if there are conflict markers
if ! echo "$output" | grep -q "<<<<<<<"; then
echo "✅ No merge conflicts. Merge should be clean."
return 0
fi
echo "⚠️ Potential merge conflicts detected:"
echo "--------------------------------------"
# Colorize the output
echo "$output" | sed \
-e 's/^<<<<<<< .*/\x1b[41;97m&\x1b[0m/' \ # Red background for HEAD
-e 's/^=======/\x1b[43;30m&\x1b[0m/' \ # Yellow background for separator
-e 's/^>>>>>>> .*/\x1b[42;97m&\x1b[0m/' \ # Green background for incoming
-e 's/^+/\x1b[32m&\x1b[0m/' \ # Green text for additions
-e 's/^-/\x1b[31m&\x1b[0m/' # Red text for deletions
echo "--------------------------------------"
}
step-by-step explanation
check git repository
git rev-parse --is-inside-work-tree
- verifies that you are inside a Git repository.
- if not, the function exits safely.
identify upstream branch
upstream=$(git rev-parse --abbrev-ref --symbolic-full-name @{upstream})
- finds the remote branch your current branch is tracking.
- needed to know which branch to compare against.
fetch latest remote changes
git fetch
- updates remote references locally without modifying files.
- safe: your working tree stays unchanged.
find merge base
base=$(git merge-base HEAD "$upstream")
- determines the common ancestor commit of your branch and upstream.
- used for a three-way merge simulation.
simulate the merge
output=$(git merge-tree "$base" HEAD "$upstream")
- performs an in-memory merge
- does not modify working tree or index
- produces conflict markers where changes overlap
detect conflicts
if ! echo "$output" | grep -q "<<<<<<<"; then
echo "✅ No merge conflicts. Merge should be clean."
return 0
fi
- checks if any conflict markers exist in the simulated merge.
- if none, the merge is safe and clean.
colorize conflict output
echo "$output" | sed \
-e 's/^<<<<<<< .*/\x1b[41;97m&\x1b[0m/' \
-e 's/^=======/\x1b[43;30m&\x1b[0m/' \
-e 's/^>>>>>>> .*/\x1b[42;97m&\x1b[0m/' \
-e 's/^+/\x1b[32m&\x1b[0m/' \
-e 's/^-/\x1b[31m&\x1b[0m/'
-
adds ANSI color codes for easier reading:
- Red background → HEAD (local)
- Yellow background → separator
- Green background → upstream changes
-
Red/Green text → deletions/additions
combined preview of merge conflicts and uncommitted changes that would block git pull
A custom shell function to check whether a Git branch is safe to pull. It provides:
- Local branch ahead/behind status relative to its upstream.
- Warnings for uncommitted or modified tracked files that could block a pull.
- Warnings for untracked files (
??) that may block a merge if the remote has files with the same name. - Optional detection of potential merge conflicts if the branch has diverged.
This function is designed as a safety check before running git pull, giving you a clear picture of any issues that might prevent a clean merge.
command
git_pull_check
example output
⚠️ Local changes that may block pull:
M file1.py
M file2.py
ℹ️ Untracked files (safe for pull unless remote has same path):
?? new_file.txt
Local branch: feature-xyz
Tracking: origin/feature-xyz
Ahead: 2 commits
Behind: 1 commit
⚠️ Branch has diverged. Checking potential merge conflicts...
⚠️ Potential merge conflicts detected:
--------------------------------------
<<<<<<< HEAD
some local line
=======
some remote line
>>>>>>> origin/feature-xyz
--------------------------------------
❌ Cannot safely pull: local changes may block merge.
underlying function
function definition
git_pull_check() {
# Ensure inside Git repo
git rev-parse --is-inside-work-tree >/dev/null 2>&1 || {
echo "Not inside a Git repository."
return 1
}
# Check upstream
UPSTREAM=$(git rev-parse --abbrev-ref --symbolic-full-name @{u} 2>/dev/null)
if [ -z "$UPSTREAM" ]; then
echo "No upstream branch set. Use: git branch -u origin/<branch>"
return 1
fi
# Fetch remote
git fetch >/dev/null
# Check working directory
STATUS=$(git status --porcelain)
MODIFIED=$(echo "$STATUS" | grep -E '^[ MADRC]')
UNTRACKED=$(echo "$STATUS" | grep '^??')
if [ -n "$MODIFIED" ]; then
echo "⚠️ Local changes that may block pull:"
echo "$MODIFIED"
BLOCK_FLAG=1
else
BLOCK_FLAG=0
fi
if [ -n "$UNTRACKED" ]; then
echo "ℹ️ Untracked files (safe for pull unless remote has same path):"
echo "$UNTRACKED"
fi
# Ahead / behind
AHEAD=$(git rev-list --count @{u}..HEAD)
BEHIND=$(git rev-list --count HEAD..@{u})
echo "Local branch: $(git branch --show-current)"
echo "Tracking: $UPSTREAM"
echo "Ahead: $AHEAD commits"
echo "Behind: $BEHIND commits"
# Determine pull status
if [ "$BLOCK_FLAG" -eq 1 ]; then
echo "❌ Cannot safely pull: local changes may block merge."
return 1
fi
if [ "$BEHIND" -gt 0 ] && [ "$AHEAD" -eq 0 ]; then
echo "✅ Safe to pull: remote has new commits, fast-forward possible."
return 0
elif [ "$BEHIND" -eq 0 ] && [ "$AHEAD" -gt 0 ]; then
echo "⚠️ You have local commits not pushed. Pull not needed."
return 0
elif [ "$BEHIND" -gt 0 ] && [ "$AHEAD" -gt 0 ]; then
echo "⚠️ Branch has diverged. Checking potential merge conflicts..."
BASE=$(git merge-base HEAD "$UPSTREAM")
OUTPUT=$(git merge-tree "$BASE" HEAD "$UPSTREAM")
if ! echo "$OUTPUT" | grep -q "<<<<<<<"; then
echo "✅ No merge conflicts detected. Merge should be clean."
else
echo "⚠️ Potential merge conflicts detected:"
echo "--------------------------------------"
echo "$OUTPUT" | sed \
-e 's/^<<<<<<< .*/\x1b[41;97m&\x1b[0m/' \
-e 's/^=======/\x1b[43;30m&\x1b[0m/' \
-e 's/^>>>>>>> .*/\x1b[42;97m&\x1b[0m/' \
-e 's/^+/\x1b[32m&\x1b[0m/' \
-e 's/^-/\x1b[31m&\x1b[0m/'
echo "--------------------------------------"
fi
return 1
else
echo "✔ Up-to-date with remote."
return 0
fi
}
line-by-line function explanation
verify you’re in a Git repository
git rev-parse --is-inside-work-tree >/dev/null 2>&1 || {
echo "Not inside a Git repository."
return 1
}
- Checks if the current directory is inside a Git repository.
- If not, prints an error and exits.
determine the upstream branch
UPSTREAM=$(git rev-parse --abbrev-ref --symbolic-full-name @{u} 2>/dev/null)
if [ -z "$UPSTREAM" ]; then
echo "No upstream branch set. Use: git branch -u origin/<branch>"
return 1
fi
- gets the name of the upstream branch (tracking branch).
- if there’s no upstream set, prints instructions and exits.
fetch the latest remote changes
git fetch >/dev/null
- fetches the latest remote changes quietly (without printing output).
identify modified tracked files (which block pull).
STATUS=$(git status --porcelain)
MODIFIED=$(echo "$STATUS" | grep -E '^[ MADRC]')
UNTRACKED=$(echo "$STATUS" | grep '^??')
git status --porcelaingives a machine-readable status of the working directory.MODIFIED→ lines indicating modified/staged files that can block a pull (M,A,D, etc.).UNTRACKED→ lines starting with??, which are untracked files (informational).
identify untracked files (informational only).
if [ -n "$MODIFIED" ]; then
echo "⚠️ Local changes that may block pull:"
echo "$MODIFIED"
BLOCK_FLAG=1
else
BLOCK_FLAG=0
fi
- if there are modified/staged files, print a warning and mark
BLOCK_FLAG. - yhese files can block a pull if a remote merge would overwrite them.
Calculate ahead/behind commit counts relative to upstream.
if [ -n "$UNTRACKED" ]; then
echo "ℹ️ Untracked files (safe for pull unless remote has same path):"
echo "$UNTRACKED"
fi
- prints untracked files separately for information.
- normally, untracked files do not block a pull unless remote has a file with the same name.
check for divergence and potential merge conflicts.
AHEAD=$(git rev-list --count @{u}..HEAD)
BEHIND=$(git rev-list --count HEAD..@{u})
- counts commits ahead (local commits not in remote) and behind (remote commits not in local).
- helps determine if the branch can be fast-forwarded or has diverged.
output a clear summary of pull safety.
echo "Local branch: $(git branch --show-current)"
echo "Tracking: $UPSTREAM"
echo "Ahead: $AHEAD commits"
echo "Behind: $BEHIND commits"
- prints a summary of the branch and its relationship to upstream.
if [ "$BLOCK_FLAG" -eq 1 ]; then
echo "❌ Cannot safely pull: local changes may block merge."
return 1
fi
- Stops the function if local modified files exist, since pull could fail.
if [ "$BEHIND" -gt 0 ] && [ "$AHEAD" -eq 0 ]; then
echo "✅ Safe to pull: remote has new commits, fast-forward possible."
return 0
elif [ "$BEHIND" -eq 0 ] && [ "$AHEAD" -gt 0 ]; then
echo "⚠️ You have local commits not pushed. Pull not needed."
return 0
elif [ "$BEHIND" -gt 0 ] && [ "$AHEAD" -gt 0 ]; then
echo "⚠️ Branch has diverged. Checking potential merge conflicts..."
BASE=$(git merge-base HEAD "$UPSTREAM")
OUTPUT=$(git merge-tree "$BASE" HEAD "$UPSTREAM")
if ! echo "$OUTPUT" | grep -q "<<<<<<<"; then
echo "✅ No merge conflicts detected. Merge should be clean."
else
echo "⚠️ Potential merge conflicts detected:"
echo "--------------------------------------"
echo "$OUTPUT" | sed \
-e 's/^<<<<<<< .*/\x1b[41;97m&\x1b[0m/' \
-e 's/^=======/\x1b[43;30m&\x1b[0m/' \
-e 's/^>>>>>>> .*/\x1b[42;97m&\x1b[0m/' \
-e 's/^+/\x1b[32m&\x1b[0m/' \
-e 's/^-/\x1b[31m&\x1b[0m/'
echo "--------------------------------------"
fi
return 1
else
echo "✔ Up-to-date with remote."
return 0
fi
- Branch behind, ahead=0 → safe to fast-forward.
- Branch ahead, behind=0 → no pull needed.
- Branch ahead & behind → diverged, potential merge conflicts detected using
git merge-tree. -
Conflicts are highlighted in color:
<<<<<<< HEAD→ local changes=======→ separator>>>>>>> remote→ remote changes+→ added lines (green)-→ removed lines (red)
- If no divergence → prints “Up-to-date.”
get git commits from a specific author
basic
git log --all --author="$AUTHOR_GITHUB_ID" --pretty=format:"%h %an %ad %s"
Here:
%h: short hash%an: author name%ad: author date%s: subject (commit message)
search across branches
as is
git for-each-ref --format="%(refname:short)" refs/heads/ | while read branch
do
echo "== $branch =="
git log "$branch" --author="Salman" --pretty=format:"%h %s"
echo
done
in a table
git-author-commits() {
if [ -z "$1" ]; then
echo "Usage: git-author-commits <author name or email>"
return 1
fi
for c in $(git log --all --author="$1" --pretty=format:"%H"); do
echo "---------"
echo "Commit: $c"
git show -s --pretty=format:"Author: %an <%ae>%nDate: %ad%nMessage:%n %s" "$c"
echo "Branches:"
git branch --all --contains "$c" | sed 's/^/ /'
echo
done
}
visualize branch divergence and merging via graph
command
git log --graph --oneline --decorate
example output
* 37c8281 (HEAD -> organization_and_docs) Merge remote-tracking branch 'refs/remotes/origin/organization_and_docs'
|\
| * 6c82ea9 (origin/organization_and_docs) add missing required files for hydrolysis
| * 8c57f13 fix hydrolysis codes for different atom naming convention
* | 4127be0 (origin/main, origin/epoxy, origin/HEAD, epoxy) Merge pull request #19
|\|
| * 87bdc6c modify correcting routine to read reacting atom indices
| * 463a651 additional correcting routine message
- a branch structure diagram (ASCII graph)
- each commit on one line
- with branch names and tags clearly shown next to commits
option-by-option Explanation
--graph
visually draws the branch structure in ASCII characters:
*marks commits|,\,/show how branches diverge and merge
example:
* 37c8281 Merge branch 'origin/organization_and_docs'
|\
| * 6c82ea9 add missing required files for hydrolysis
--oneline
compresses each commit to a single line, using:
- the short commit hash (7 characters)
- the first line of the commit message
so instead of:
commit 87bdc6c0c1aa0408ca7f9f2030200b...
Author: Salman
Date: Mon Dec 8 16:00:00 2025
modify correcting routine to read indices
you see:
87bdc6c modify correcting routine to read indices
--decorate
displays branch names, tags, and HEAD pointers next to the commits.
example:
37c8281 (HEAD -> organization_and_docs) Merge remote-tracking branch 'origin/organization_and_docs'
4127be0 (origin/main, origin/epoxy, origin/HEAD, epoxy) Merge pull request #19
this shows:
- where
HEADis - what branch a commit belongs to
- what tags point to which commit
- what the remote tracking branch is (
origin/main)
this is essential to understand the state of your branches.
--all (highly recommended)
to get a full repository overview. this section will be developed further later.