Skip to main content

Command Palette

Search for a command to run...

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

Published
17 min read
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 here

  • push = 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:

  1. Navigate to /usr/src/kodekloudrepos/apps/

  2. Create/edit files

  3. Commit changes locally

  4. Push to central repository

  5. Collaborate with team members

  6. 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! 🔄

More from this blog

🚀 DevOps Challenge- KodeKloud Solutions

73 posts