Day 22: Cloning Git Repository on Storage Server - Setting Up Development Workflow 🔄

Welcome back! 👋 Day 22 of the 100 Days Cloud DevOps Challenge, and today we're cloning a Git repository to make it accessible for the development team! This is how teams start working with version control - cloning the central repository to begin development. Let's make it happen! 🎯
🎯 The Mission - Repository Distribution
It's Monday morning, and the development team needs access to the Git repository:
📋 TASK TICKET #DEV-6023 - Clone Git Repository
Priority: MEDIUM
Type: Version Control Setup - Repository Distribution
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
PROJECT: Apps Repository Distribution
Target: Storage Server (ststor01)
User: natasha
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
BACKGROUND:
└─ Git repository created last week: /opt/apps.git
└─ Currently unused (no commits yet)
└─ Development team needs working copy
REQUIREMENTS:
1. Source Repository:
└─ Location: /opt/apps.git (bare repository)
└─ Status: Empty but initialized
2. Clone Destination:
└─ Target directory: /usr/src/kodekloudrepos
└─ User: natasha (NOT root!)
└─ Result: Normal repository (with working directory)
3. Constraints:
└─ DO NOT modify source repository
└─ DO NOT change any permissions
└─ DO NOT alter existing directories
└─ Use natasha user for all operations
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
STATUS: READY TO START
DEADLINE: Today
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
This is how developers start working with Git! Clone once, work forever! 🏗️
🤔 Why This Matters - Understanding Git Clone
The Development Workflow
Without Git Clone:
Central Repository (server)
└─ /opt/apps.git (bare)
Developer:
"I need to work on this code..."
"How do I get the files?"
"How do I contribute?"
❌ No clear workflow!
With Git Clone (What We're Setting Up):
Central Repository (server)
└─ /opt/apps.git (bare)
↓ (git clone)
Working Copy (local)
└─ /usr/src/kodekloudrepos/apps/
├─ .git/ (full history)
└─ Working files (editable)
Developer can now:
✅ Edit files locally
✅ Commit changes
✅ Create branches
✅ Push back to central repo
✅ Pull others' changes
Real stat: Every developer clones repositories thousands of times in their career! It's the starting point of all Git workflows! 📊
Understanding Git Clone Process
What happens when you clone:
Step 1: Create Local Directory
$ git clone /opt/apps.git
Step 2: Copy Git Database
Local .git/ ← copies from → Remote /opt/apps.git/
├─ All commits
├─ All branches
├─ All tags
└─ Complete history
Step 3: Set Up Remote
Local git config:
[remote "origin"]
url = /opt/apps.git
fetch = +refs/heads/*:refs/remotes/origin/*
Step 4: Checkout Working Directory
(If repository has commits)
Extracts latest version of files
Result: Full, independent copy!
Key insight: Clone creates a COMPLETE copy, not just current files!
Clone vs Copy: Critical Difference
Regular File Copy (Wrong Way):
# Don't do this!
cp -r /opt/apps.git /usr/src/kodekloudrepos/apps
Result:
❌ Copies bare repository structure
❌ No working directory
❌ Can't edit files
❌ No connection to original
❌ No Git commands work properly
Git Clone (Right Way):
# Correct approach!
git clone /opt/apps.git /usr/src/kodekloudrepos/apps
Result:
✅ Creates normal repository
✅ Has working directory
✅ Can edit files
✅ Connected to original ("origin" remote)
✅ All Git commands work
✅ Can pull/push changes
Real-World Analogy
Think of it like this:
Bare Repository (/opt/apps.git) = Library (books stored, no reading room)
Cloned Repository (/usr/src/kodekloudrepos/apps/) = Borrowed Book + Library Card (can read, take notes, return with notes)
You don't work in the library - you clone (borrow) to work elsewhere!
🏗️ Understanding the Setup
Current State:
Storage Server (ststor01)
├─ /opt/apps.git/ ← Bare repository (exists)
│ ├─ HEAD
│ ├─ config (bare = true)
│ ├─ objects/
│ └─ refs/
│
└─ /usr/src/kodekloudrepos/ ← Target directory (may not exist)
└─ (empty or doesn't exist)
After Our Setup:
Storage Server (ststor01)
├─ /opt/apps.git/ ← Source (unchanged)
│ ├─ objects/
│ └─ refs/
│
└─ /usr/src/kodekloudrepos/ ← Clone destination
└─ apps/ ← Cloned repository
├─ .git/ ← Git database (normal repo)
│ ├─ objects/ (copy of source)
│ ├─ refs/
│ └─ config (bare = false!)
│ [remote "origin"]
│ url = /opt/apps.git
│
└─ (working files when commits exist)
The Flow:
1. natasha logs in to storage server
↓
2. Navigate to /usr/src/kodekloudrepos
(create if doesn't exist)
↓
3. Clone: git clone /opt/apps.git apps
↓
4. Git creates apps/ directory
↓
5. Git copies all data from /opt/apps.git
↓
6. Git sets up remote "origin"
↓
7. Ready for development!
🛠️ Phase 1: Preparation
Step 1.1: SSH to Storage Server
# From Jump Host, connect as natasha
ssh natasha@ststor01
# Password: Bl@kW (or your lab credentials)
You're now logged in as natasha! ✅
Important: We're staying as natasha user throughout this task - NO sudo su -!
Step 1.2: Verify Source Repository Exists
# Check if source repository exists
ls -la /opt/apps.git/
Expected output:
drwxr-xr-x. 7 root root 119 Nov 26 10:00 .
drwxr-xr-x. 3 root root 28 Nov 26 10:00 ..
drwxr-xr-x. 2 root root 6 Nov 26 10:00 branches
-rw-r--r--. 1 root root 66 Nov 26 10:00 config
-rw-r--r--. 1 root root 73 Nov 26 10:00 description
-rw-r--r--. 1 root root 23 Nov 26 10:00 HEAD
drwxr-xr-x. 2 root root 4096 Nov 26 10:00 hooks
drwxr-xr-x. 2 root root 21 Nov 26 10:00 info
drwxr-xr-x. 4 root root 30 Nov 26 10:00 objects
drwxr-xr-x. 4 root root 31 Nov 26 10:00 refs
Source repository exists and is readable! ✅
Step 1.3: Check Target Directory
# Check if target directory exists
ls -la /usr/src/kodekloudrepos/ 2>/dev/null || echo "Directory doesn't exist"
If directory doesn't exist:
Directory doesn't exist
That's okay! We need to create it.
If directory exists but is empty:
total 8
drwxr-xr-x. 2 natasha natasha 4096 Nov 26 10:00 .
drwxr-xr-x. 3 root root 4096 Nov 26 10:00 ..
Perfect - ready to clone! ✅
🛠️ Phase 2: Create Target Directory
Step 2.1: Create Directory (If Needed)
# Create the target directory
sudo mkdir -p /usr/src/kodekloudrepos
Output: (Usually silent if successful)
Verify directory was created:
ls -ld /usr/src/kodekloudrepos
Expected output:
drwxr-xr-x. 2 root root 6 Nov 26 10:15 /usr/src/kodekloudrepos
Directory created but owned by root! ✅
Step 2.2: Set Proper Permissions
# Change ownership to natasha so we can write to it
sudo chown natasha:natasha /usr/src/kodekloudrepos
Verify ownership:
ls -ld /usr/src/kodekloudrepos
Expected output:
drwxr-xr-x. 2 natasha natasha 6 Nov 26 10:15 /usr/src/kodekloudrepos
Now owned by natasha! ✅
Important: We need write permission to create the cloned repository inside this directory.
🛠️ Phase 3: Clone the Repository
Step 3.1: Navigate to Target Directory
# Change to target directory
cd /usr/src/kodekloudrepos
Verify you're in the right location:
pwd
Output: /usr/src/kodekloudrepos
Ready to clone! ✅
Step 3.2: Clone the Repository
# Clone the bare repository
git clone /opt/apps.git
Expected output:
Cloning into 'apps'...
warning: You appear to have cloned an empty repository.
done.
What just happened:
✅ Git created
apps/directory✅ Copied all data from
/opt/apps.git✅ Set up remote "origin"
⚠️ Warning is normal - repository has no commits yet!
Alternative: Specify Target Name
If you want to name it differently:
# Clone with custom name
git clone /opt/apps.git custom-name
But we'll use default name apps which matches source!
Step 3.3: Verify Clone Was Successful
# List directory contents
ls -la /usr/src/kodekloudrepos/
Expected output:
total 12
drwxr-xr-x. 3 natasha natasha 4096 Nov 26 10:20 .
drwxr-xr-x. 3 root root 4096 Nov 26 10:15 ..
drwxr-xr-x. 3 natasha natasha 4096 Nov 26 10:20 apps
apps/ directory created! ✅
Check inside the cloned repository:
ls -la /usr/src/kodekloudrepos/apps/
Expected output:
total 12
drwxr-xr-x. 3 natasha natasha 4096 Nov 26 10:20 .
drwxr-xr-x. 3 natasha natasha 4096 Nov 26 10:20 ..
drwxr-xr-x. 7 natasha natasha 4096 Nov 26 10:20 .git
Only .git/ directory exists (because repository is empty - no files committed yet).
This is correct! ✅
🛠️ Phase 4: Verify Repository Configuration
Step 4.1: Check Repository Type
# Enter cloned repository
cd /usr/src/kodekloudrepos/apps
# Check if it's a normal repository (not bare)
git config --get core.bare
Expected output: false
Perfect! It's a normal repository with working directory! ✅
Step 4.2: Check Remote Configuration
# View remote configuration
git remote -v
Expected output:
origin /opt/apps.git (fetch)
origin /opt/apps.git (push)
Explanation:
origin= default name for source repository/opt/apps.git= path to source (bare repository)fetch= can pull changes from herepush= can push changes to here
Remote configured correctly! ✅
Step 4.3: View Complete Configuration
# Show repository configuration
cat .git/config
Expected output:
[core]
repositoryformatversion = 0
filemode = true
bare = false
logallrefupdates = true
[remote "origin"]
url = /opt/apps.git
fetch = +refs/heads/*:refs/remotes/origin/*
[branch "master"]
remote = origin
merge = refs/heads/master
Key points:
✅
bare = false(normal repository)✅
remote "origin"points to/opt/apps.git✅ Branch tracking configured
Step 4.4: Check Repository Status
# Check current status
git status
Expected output:
On branch master
No commits yet
nothing to commit (create/copy files and use "git add" to track)
Or for newer Git versions:
On branch main
No commits yet
nothing to commit (create/copy files and use "git add" to track)
Status is clean! Repository is ready for development! ✅
🎉 Phase 5: Complete Verification
Step 5.1: Verify Directory Structure
# Full path verification
pwd
Output: /usr/src/kodekloudrepos/apps
# Check .git directory structure
ls -la .git/
Expected output:
total 16
drwxr-xr-x. 7 natasha natasha 119 Nov 26 10:20 .
drwxr-xr-x. 3 natasha natasha 18 Nov 26 10:20 ..
drwxr-xr-x. 2 natasha natasha 6 Nov 26 10:20 branches
-rw-r--r--. 1 natasha natasha 143 Nov 26 10:20 config
-rw-r--r--. 1 natasha natasha 73 Nov 26 10:20 description
-rw-r--r--. 1 natasha natasha 23 Nov 26 10:20 HEAD
drwxr-xr-x. 2 natasha natasha 4096 Nov 26 10:20 hooks
drwxr-xr-x. 2 natasha natasha 21 Nov 26 10:20 info
drwxr-xr-x. 4 natasha natasha 30 Nov 26 10:20 objects
drwxr-xr-x. 4 natasha natasha 31 Nov 26 10:20 refs
All Git infrastructure in place! ✅
Step 5.2: Test Git Commands
# Test various Git commands
git log # Should show "fatal: your current branch 'master' does not have any commits yet"
git branch # Should list current branch
git remote show origin # Should show remote details
All Git commands work! ✅
Step 5.3: Verify Permissions
# Check ownership of entire cloned repo
ls -la /usr/src/kodekloudrepos/
Expected:
drwxr-xr-x. 3 natasha natasha 4096 Nov 26 10:20 apps
Owned by natasha! ✅
Check we didn't modify source:
ls -ld /opt/apps.git
Should still show:
drwxr-xr-x. 7 root root 119 Nov 26 10:00 /opt/apps.git
Source unchanged! ✅
CLONE OPERATION COMPLETE! 🎉🎊🎈
🔍 Understanding What We Accomplished
Before vs After
Before:
Storage Server
├─ /opt/apps.git ← Bare repo (exists)
│ └─ No working directory
│
└─ /usr/src/kodekloudrepos ← Empty or doesn't exist
After:
Storage Server
├─ /opt/apps.git ← Bare repo (UNCHANGED)
│ └─ Still no working directory
│
└─ /usr/src/kodekloudrepos/ ← Created with proper permissions
└─ apps/ ← Cloned repository
├─ .git/ ← Full Git database
│ ├─ config ← Points to origin
│ └─ objects/ ← Copy of source data
│
└─ (working directory - empty until commits)
Repository Relationship
Bare Repository (Central)
/opt/apps.git/
↑ push
↓ pull/fetch
Normal Repository (Working Copy)
/usr/src/kodekloudrepos/apps/
Connection:
├─ Origin remote: /opt/apps.git
├─ Can pull updates from origin
├─ Can push changes to origin
└─ Independent working directory
What Developers Can Now Do
# Navigate to repository
cd /usr/src/kodekloudrepos/apps
# Create new file
echo "# Apps Project" > README.md
# Stage and commit
git add README.md
git commit -m "Initial commit: Add README"
# Push to central repository
git push origin master
# Other developers can then:
cd /some/other/location
git clone /opt/apps.git
# And get the README.md file!
💡 Key Takeaways
✨ git clone creates a complete, independent copy of repository ✨ Clone creates normal repository from bare repository ✨ Origin remote automatically configured to source ✨ Working directory included (unlike bare repos) ✨ Complete history copied (all commits, branches, tags) ✨ Permissions matter - need write access to target directory ✨ Empty repos clone successfully (with warning) ✨ Source unchanged - clone doesn't modify original ✨ Use natasha user - follows principle of least privilege ✨ Directory creation may be needed before cloning ✨ git config --get core.bare verifies repository type
🎓 Interview Questions
Q1: Explain the difference between git clone and copying the repository directory with cp -r. Why does the difference matter?
Answer: These operations produce fundamentally different results. cp -r /opt/apps.git /dest/: Copies files and directories recursively as-is. If copying bare repository, destination is also bare (no working directory). No Git configuration for remotes. No connection to source. Result is static copy, not functional Git repo. git clone /opt/apps.git /dest/apps: Creates normal repository from bare repo with working directory. Sets up remote "origin" pointing to source. Copies complete Git history and structure. Configures branch tracking. Result is fully functional development environment. Why it matters: Copied bare repo can't be used for development (no working directory, can't checkout files). Cloned repo is ready for development immediately. Clone maintains connection to source for pull/push. Clone converts bare to normal automatically. Real-world scenario: Developer copies bare repo instead of cloning - can't edit files, can't commit, confused why Git commands fail. Correct approach: Always use git clone to create working copies. Use cp only for bare-to-bare backups. Pro tip: git clone --bare creates bare copy if that's intentionally needed.
Q2: What does the "origin" remote represent in a cloned repository, and how can you verify or modify it?
Answer: "Origin" is the default name Git assigns to the remote repository you cloned from. What it represents: URL/path to source repository, reference point for push/pull operations, conceptual "source of truth", starting point of repository history. View origin: git remote -v shows all remotes with URLs. git remote show origin shows detailed info (fetch/push URLs, tracked branches). cat .git/config shows raw configuration including [remote "origin"] section. Modify origin URL: git remote set-url origin new-url changes where origin points. Example: git remote set-url origin user@server:/new/path/repo.git. Useful when: Migrating to new server, switching protocols (HTTPS to SSH), updating server hostname. Add additional remotes: git remote add upstream /other/repo.git for multiple sources. Common pattern: origin = your fork, upstream = original project. Remove origin: git remote remove origin (rarely needed). Why "origin" name: Convention only - could name it anything. Most workflows assume "origin" exists, so changing name causes confusion. Best practice: Keep "origin" as primary/authoritative repository. Add other remotes with descriptive names (upstream, backup, staging).
Q3: The repository you cloned is empty (no commits). Walk through what happens when someone makes the first commit and pushes it.
Answer: Step-by-step flow for first commit and push: Initial state: Both bare and cloned repos initialized but empty, no branches exist yet (refs/heads/ empty), HEAD points to non-existent master/main. Developer creates first commit: In /usr/src/kodekloudrepos/apps/: Create file: echo "# Project" > README.md. Stage: git add README.md. Commit: git commit -m "Initial commit". What Git creates locally: Blob object for README.md content (stores actual file), tree object (directory structure), commit object (metadata, message, points to tree), refs/heads/master now points to this commit, working directory updated with files. Developer pushes: git push origin master. Push process: Local Git connects to /opt/apps.git (origin), negotiates - server has no commits, local has 1, local sends objects (commit, tree, blob) to server, server stores objects in objects/ directory. Server updates: Creates refs/heads/master pointing to new commit, updates info/refs for Git protocols, triggers post-receive hooks if configured. Other developers: Can now clone and get README.md, can see commit in history with git log, can pull to existing clones with git pull. Subsequent commits: Add more objects and update refs, no longer "empty" warning. First commit is special: Establishes default branch name (master/main), creates initial history root, enables branch tracking.
Q4: What permissions are needed for different Git operations on the cloned repository?
Answer: Git operations require different permission levels: Read operations (safe): git log, git status, git diff, git show - need READ permission on .git/ directory and contents, can run by any user with access, don't modify repository. Local write operations (working directory): git add, git commit, git stash - need WRITE permission on .git/ and working directory, create new objects in .git/objects/, update .git/index (staging area), user running commands must own files or have write access. Remote operations (network): git fetch, git pull - need READ access to remote repository, WRITE access to local .git/refs/, downloads objects and updates references. git push - need WRITE access to remote repository (on server), READ access to local repository, server permissions determine if push succeeds. Our scenario permissions: Repository owned by natasha:natasha, natasha can perform all local operations, for push to /opt/apps.git (owned by root), natasha needs write access to /opt/apps.git or use different authentication. Production recommendations: Use SSH keys for remote access, set group permissions for shared access: chmod -R 775 repo.git, chgrp developers repo.git, use Gitolite/GitLab for fine-grained access control. Common permission issues: "Permission denied" on commit - user doesn't own .git/, "Permission denied" on push - no write access to remote, "Permission denied" on clone - can't read source or write to destination.
Q5: How would you handle cloning a very large repository (10GB+) efficiently?
Answer: Large repository cloning strategies: 1) Shallow clone (most common): git clone --depth 1 /opt/apps.git - clones only latest commit, no history. Reduces size by 90%+ typically. Good for: CI/CD builds, quick testing, deployment. Limitations: can't see history, limited branching. 2) Partial clone (Git 2.17+): git clone --filter=blob:none /opt/apps.git - downloads commits and trees immediately, downloads blobs (file contents) on demand. Faster initial clone, downloads files as needed. 3) Shallow with single branch: git clone --depth 1 --single-branch --branch main /opt/apps.git - only gets specified branch. Useful when: Only need one branch, working on specific feature. 4) Gradual deepening: Start shallow: git clone --depth 1, later increase: git fetch --deepen=100, or full history: git fetch --unshallow. 5) Git LFS (Large File Storage): For repos with large binaries, git lfs clone downloads LFS pointers, large files downloaded separately on checkout. 6) Bandwidth optimization: git clone --progress shows progress, git clone -c http.postBuffer=524288000 increases buffer for large repos. Real-world example: Linux kernel repo is 3GB+. Shallow clone: 200MB in 30 seconds. Full clone: 3GB in 10 minutes. Best practices: Use shallow clones for automation, full clones for development, consider Git LFS for binary assets, monitor clone times in CI/CD.
Q6: What's the difference between git clone /path/repo.git (filesystem) and git clone user@host:/path/repo.git (SSH)?
Answer: Both clone repositories but use different access methods: Filesystem clone (git clone /path/repo.git): How it works: Direct filesystem access, reads files locally, no network protocols. Requirements: Source and destination on same machine or shared filesystem (NFS, SMB), no authentication needed (uses filesystem permissions), fastest method (no network overhead). Use cases: Same server clones, local development, server-to-server with shared storage. Limitations: Requires local/mounted access, can't clone across network without shared filesystem. Our task uses this method: Source: /opt/apps.git (local path), destination: /usr/src/kodekloudrepos/apps (same server). SSH clone (git clone user@host:/path/repo.git): How it works: SSH protocol, network connection, authentication required (password/keys), Git protocol over SSH. Requirements: SSH access to remote server, user credentials (password/SSH key), network connectivity. Use cases: Cloning from remote servers, standard development workflow, production deployments. Advantages: Works across networks, secure authentication and encryption, standard in professional environments. Format variations: git clone ssh://user@host/path/repo.git (explicit SSH), git clone user@host:path/repo.git (SCP-style), git clone git@github.com:user/repo.git (GitHub standard). Performance: Filesystem fastest (direct I/O), SSH has network overhead but encrypted. Best practices: Use filesystem for same-server operations, use SSH for remote/production, configure SSH keys for automation, use HTTPS as fallback (firewall-friendly).
🚨 Common Issues and Solutions
Issue 1: Permission Denied Creating Directory
# Error:
mkdir: cannot create directory '/usr/src/kodekloudrepos': Permission denied
# Solution:
sudo mkdir -p /usr/src/kodekloudrepos
sudo chown natasha:natasha /usr/src/kodekloudrepos
Issue 2: Cannot Access Source Repository
# Error:
fatal: could not create work tree dir 'apps': Permission denied
# Check source is readable:
ls -la /opt/apps.git/
# If not readable by natasha:
sudo chmod -R 755 /opt/apps.git
Issue 3: Repository Already Exists
# Error:
fatal: destination path 'apps' already exists
# Check what's there:
ls -la /usr/src/kodekloudrepos/apps/
# If needed, remove and reclone:
rm -rf /usr/src/kodekloudrepos/apps
git clone /opt/apps.git /usr/src/kodekloudrepos/apps
Issue 4: Wrong Directory
# Cloned to wrong location
# Correct: /usr/src/kodekloudrepos/apps
# Wrong: /usr/src/apps
# Move it:
mv /usr/src/apps /usr/src/kodekloudrepos/
🌟 Final Thoughts
You've successfully cloned a Git repository, setting up the foundation for team development! This is exactly how professional developers start working on projects.
What you accomplished:
✅ Created target directory with proper permissions
✅ Cloned bare repository to normal repository
✅ Verified remote configuration
✅ Confirmed repository is ready for development
✅ Used natasha user (non-root) following security best practices
Real-world impact: This workflow is used billions of times daily:
Developers cloning GitHub repositories
CI/CD pipelines cloning code for builds
Deployment systems pulling latest code
Teams starting new projects
What the development team can now do:
Navigate to
/usr/src/kodekloudrepos/apps/Create/edit files
Commit changes locally
Push to central repository
Collaborate with team members
Track complete project history
This is professional software development! 💪
🚀 What's Next?
Day 22 complete! 🎉 You've mastered Git repository cloning!
Skills Mastered Today:
✅ Git clone operations
✅ Repository type conversion (bare to normal)
✅ Remote configuration understanding
✅ Permission management for Git operations
✅ Directory preparation for cloning
Tomorrow, Day 23 awaits! Keep building! 💪
Day: 22/100
Challenge: KodeKloud Cloud DevOps
Date: November 26, 2025
Topic: Git Repository Cloning - Development Workflow Setup
How many repositories have you cloned in your career? What's your favorite Git workflow? Share your experiences! 🔄




