What is git repository corruption from cloud sync?
Git repository corruption from cloud sync is a class of data integrity failures caused when file synchronization services like iCloud, Dropbox, OneDrive, or Google Drive monitor and sync the contents of a .git directory. Git stores its data as a transactional database across multiple interdependent files: objects, pack files, refs, the index, and HEAD. Cloud sync engines watch for individual file changes and upload them independently, breaking the atomic relationships between these files.
This produces 10 documented failure modes including lockfile races, partial pack writes, ref pointer overwrites, and object eviction. Each mechanism results in specific terminal errors like fatal: bad object HEAD or error: packfile does not match index.
The corruption is silent until git attempts a read operation that depends on consistent internal state.
Cloud sync services like iCloud, Dropbox, OneDrive, and Google Drive can silently destroy your project's version history. Your code files look fine, but the hidden .git folder that tracks all your changes gets corrupted. When that happens, you see scary error messages and your project stops working with Git.
This is not a rare edge case. It happens to thousands of developers and builders every year. Apple, Microsoft, Google, and Dropbox all know about it. None of them have fixed it.
You will not see it coming. There is no warning, no pop-up, no error when it happens. You only find out when you try to commit, push, or switch branches and Git refuses.
Cloud sync services cause a class of silent data integrity failures in git repositories. The root cause is a design-level mismatch: git's .git directory is a transactional database with atomic write requirements. Cloud sync engines treat it as a collection of independent files and sync them individually.
The result: 10 documented corruption mechanisms that produce specific, deterministic failures. Every major provider is affected. None have shipped a structural fix. None have issued developer-facing warnings.
Git's official FAQ warns against it directly: "It is important not to use a cloud syncing service to sync any portion of a Git repository." The documentation warns that cloud sync can cause "missing objects, changed or added files, broken refs, and a wide variety of other problems." This is not speculation. It is in the docs.
We wanted to know exactly how it breaks. Not "it can cause problems." Not "use caution." The specific mechanisms. The specific files. The specific error messages you see in your terminal at 2am when a deadline is tomorrow.
So we investigated how each major cloud sync service interacts with real git repositories. iCloud. Dropbox. Google Drive. OneDrive. We catalogued every documented corruption pattern, cross-referencing years of developer reports across GitHub issues, Apple Developer Forums, Stack Overflow, Hacker News, and vendor support threads.
Here are the 10 ways they break your repos.
Git's own documentation says it clearly: "It is important not to use a cloud syncing service to sync any portion of a Git repository." That warning is buried in a FAQ page most people never read.
We investigated how each service actually breaks your projects. Not vague warnings. The specific errors you see when it goes wrong. iCloud. Dropbox. Google Drive. OneDrive. All four.
Here are the 10 ways they break your projects.
Git's own FAQ states it directly: "It is important not to use a cloud syncing service to sync any portion of a Git repository." Source.
We catalogued every documented corruption mechanism across all four major providers, cross-referencing GitHub issues, vendor support threads, Apple Developer Forums, and Stack Overflow. The result: 10 distinct failure modes, each producing specific, reproducible error states.
Why git repos break in cloud-synced folders
Your .git directory is not a collection of independent files. It is a transactional database. When you run git commit, git writes a blob object, then a tree object, then a commit object, then updates a ref file, then updates the index. These writes must happen in a specific order. If any file is read between writes by another process, the state is inconsistent.
Cloud sync services do not understand this. They watch for file changes and upload them one at a time. They have no concept of "this group of 6 files must be treated as a single atomic operation." They see .git/objects/ab/cdef1234... change. They upload it. They see .git/refs/heads/main change. They upload it. If those uploads happen on another machine in a different order, or if the sync engine reads a file mid-write, the repo is broken.
The root cause is structural. Cloud sync treats files as independent units. Git treats files as a transactional database. These two models are incompatible. No amount of conflict resolution can fix this. It is a design-level mismatch.
Your project has a hidden folder called .git that keeps track of every change you have ever made. It is not just a collection of files. It is more like a database where everything has to be saved in a specific order.
Cloud sync does not understand this. It watches for file changes and uploads them one at a time. When it uploads the files in the wrong order, or reads a file while Git is still writing it, the tracking system breaks.
This is not a bug that can be fixed. Cloud sync and Git work in fundamentally different ways. Cloud sync treats every file as independent. Git treats them as one connected system. These two approaches are incompatible.
Git's .git directory is a transactional database with strict write ordering. A single git commit produces a blob, tree, commit object, ref update, and index write, in that order. Any read between writes produces inconsistent state.
Cloud sync engines have no transaction model. They detect individual file changes and propagate them independently with no ordering guarantee. When the sync engine reads .git/refs/heads/main before the commit object it references has been written, the ref is a dangling pointer. This is a fundamental design mismatch, not a configuration error.
The root cause is structural. Cloud sync provides eventual consistency for independent files. Git requires immediate consistency across dependent files. No amount of conflict resolution resolves this. The two models are incompatible.
Mechanism 01 Critical
Lockfile Races
.git/index.lock
What happens
Git creates .git/index.lock as an exclusive lock before writing to the index. This prevents two git processes from writing simultaneously. Cloud sync services do not respect this lock. They detect the lock file as "new" and sync it. They detect the index file changing and sync it. On another machine, the stale lock file arrives before the new index, blocking all git operations.
Worse, some sync services (iCloud's fileproviderd, OneDrive's sync engine) will hold open or re-download files in the middle of git writing them. The lock file becomes an orphan. Git refuses to operate until you manually delete it.
What you see
fatal: Unable to create '.git/index.lock': File exists.
Another git process seems to be running in this repository.
If no other git process is currently running, this probably
means a git process crashed earlier. Remove the file manually.
How to detect it
Check for stale lock files: find . -name "*.lock" -path "*/.git/*". If the file exists but no git process is running, your sync service created or preserved it.
Mechanism 01 Critical
Your Project Gets Stuck Because of a Ghost Lock File
.git/index.lock
What this means
When you save changes, Git creates a temporary lock file so nothing else can interfere. Cloud sync copies that lock file to your other devices, where it never gets cleaned up. Now Git thinks something else is working and refuses to do anything.
What happens
This means Git found a lock file that should not be there. Your project is not broken, it is stuck. The lock needs to be removed.
Mechanism 01 Critical
Lockfile Race Condition
.git/index.lock
Failure pattern
Git uses advisory file-level locking via index.lock to serialize concurrent operations. Cloud sync treats this lock as a regular file and propagates it across devices. The lock arrives on Machine B before the operation completes on Machine A, blocking all git operations on B with a stale lock that will never be released by the process that created it.
Observable signal
Systemic implication
Mechanism 02 Critical
Partial Pack Writes
.git/objects/pack/
What happens
When git runs garbage collection (git gc), it compresses loose objects into pack files. A pack file (.pack) and its index (.idx) are a matched pair. The pack contains the compressed objects. The index maps object SHAs to byte offsets in the pack. If one file syncs and the other does not, or if the pack file is uploaded while git is still writing it, the pair is broken.
Pack files can be tens or hundreds of megabytes. Cloud sync services upload large files in chunks. If the connection drops, or if the sync engine decides to prioritize a different file mid-upload, you get a truncated pack on the remote side. A truncated pack is unrecoverable without the original.
What you see
error: packfile .git/objects/pack/pack-abc123.pack does not match index
fatal: git-pack-objects died with error
How to detect it
Run git verify-pack -v .git/objects/pack/pack-*.idx to validate each pack against its index. Any mismatch means corruption. Run git fsck --full to find missing or broken objects.
Mechanism 02 Critical
Your Project History Gets Shredded Mid-Upload
.git/objects/pack/
What this means
Git compresses your project history into large archive files. These files come in matched pairs that must stay perfectly in sync. If cloud sync gets interrupted while uploading one, you end up with a half-written file that Git cannot read, and your history is gone.
What happens
This means the archive file holding your project history was corrupted during sync. This one is serious and usually means you need to re-download your project from GitHub.
Mechanism 02 Critical
Partial Pack Write Truncation
.git/objects/pack/
Failure pattern
Pack files consolidate hundreds of objects into a single file that can reach hundreds of MB. Cloud sync uploads in chunks with no transactional guarantee. An interrupted upload produces a truncated pack, and the corresponding .idx references offsets that no longer exist. Without the original loose objects (already garbage-collected), the data is unrecoverable.
Observable signal
Systemic implication
Mechanism 03 Critical
Index Conflicts
.git/index
What happens
The .git/index file is a binary file that tracks the state of the staging area. It maps every tracked file to its blob SHA, file mode, timestamps, and flags. It is rewritten entirely on almost every git operation. It is not mergeable. There is no "conflict resolution" strategy that works on a binary index file.
When two machines modify the index and the sync service detects a conflict, the service either overwrites one version (iCloud, OneDrive) or creates a "conflicted copy" alongside the original (Dropbox). Both outcomes corrupt the staging area. Git expects exactly one .git/index file with a valid checksum. A Dropbox-created .git/index (John's conflicted copy 2026-05-01) is invisible to git but pollutes the directory.
What you see
fatal: index file corrupt
How to detect it
Run git status. If it fails with "index file corrupt," the index has been overwritten by a sync conflict. Check for conflicted copies: ls -la .git/index*. Any file besides .git/index is evidence of sync interference.
Mechanism 03 Critical
Cloud Sync Scrambles Your "Ready to Save" List
.git/index
What this means
Git keeps a file that tracks which changes you are about to save. This file is written in a format only Git understands. Cloud sync either overwrites it with an older version or creates a duplicate, and either way Git can no longer read it.
What happens
This means Git's tracking of your staged changes is broken. Your actual code files are fine, but Git has lost track of what you were about to save.
Mechanism 03 Critical
Binary Index Conflict Resolution
.git/index
Failure pattern
The git index is a binary file with a trailing SHA-1 checksum. It encodes the entire staging area in a format that is not mergeable by any text-based strategy. Cloud sync applies text-style conflict resolution (or last-write-wins) to binary data. The checksum invalidates, and git rejects the entire staging area.
Observable signal
Systemic implication
Mechanism 04 Critical
Ref Pointer Overwrites
.git/refs/
What happens
Branch refs are tiny files. .git/refs/heads/main contains a single line: the 40-character SHA of the commit that branch points to. When you commit on Machine A, the ref updates. When Machine B syncs, the old ref may overwrite the new one. Or the new ref may arrive before the commit object it points to. Either way, the ref now points to a commit that does not exist in the local object store.
Dropbox makes this visible by creating files like refs/heads/main (MacBook-Pro's conflicted copy 2025-06-11). Git then reports "Reference has invalid format" because the parentheses in the filename are not valid ref syntax.
What you see
fatal: Reference has invalid format: 'refs/heads/main (MacBook-Pro's conflicted copy 2025-06-11)'
error: refs/heads/main does not point to a valid object
How to detect it
Run git fsck --full and look for "dangling" or "missing" errors. List all files in .git/refs/ and check for any with spaces, parentheses, or "conflicted" in the name.
Mechanism 04 Critical
Your Branches Get Pointed at the Wrong Save
.git/refs/
What this means
Each branch is a tiny file containing the ID of your latest save. Cloud sync can overwrite a newer ID with an older one, silently rolling back your branch. Dropbox sometimes creates duplicate files with your computer's name in the filename, which Git cannot understand at all.
What happens
This means Dropbox created a conflicted copy of your branch pointer. Git sees the parentheses in the filename and does not know what to do with it.
Mechanism 04 Critical
Ref Pointer Temporal Desync
.git/refs/
Failure pattern
Refs are 40-byte text files pointing to commit SHAs. Cloud sync propagates them independently from the objects they reference. A ref can arrive on Machine B before the commit object it points to, creating a dangling reference. Under last-write-wins, a stale ref silently overwrites a newer ref, rewinding branch history without any merge conflict signal.
Observable signal
Systemic implication
Mechanism 05 High
Loose Object Collisions
.git/objects/
What happens
Git stores each object (blob, tree, commit, tag) as a file named by its SHA-1 hash in .git/objects/ab/cdef.... These files are immutable. Once written, they should never change. But cloud sync services do not know this.
When iCloud or OneDrive detects that an object file was "modified" (because it was rewritten during a repack or gc), the sync engine may replace it with a zero-byte placeholder (OneDrive's Files On-Demand) or an older version from another device. The SHA in the filename no longer matches the content. Git's integrity check fails. The object is corrupt.
What you see
error: object file .git/objects/ab/cdef1234... is empty
fatal: loose object abcdef1234... (stored in .git/objects/ab/cdef1234...) is corrupt
How to detect it
Run git fsck --full --no-dangling. Any "empty" or "corrupt" object errors indicate sync interference. Check for zero-byte files: find .git/objects -type f -empty.
Mechanism 05 High
Saved Code Replaced with Empty Files
.git/objects/
What this means
Git stores every version of every file as a numbered object. These should never change once created. Cloud sync sometimes replaces them with empty placeholder files or older versions, so when Git goes to read them, the contents do not match the ID.
What happens
This means a file Git needs has been emptied out by cloud sync. The specific version of your code that object represented may be lost.
Mechanism 05 High
Content-Addressed Object Replacement
.git/objects/
Failure pattern
Git's object store is content-addressed: the filename IS the hash of the contents. Files On-Demand features replace object files with zero-byte placeholders that preserve the filename (the SHA) but discard the content. The content-addressing contract is silently violated.
Observable signal
Systemic implication
Mechanism 06 Critical
HEAD Symref Corruption
.git/HEAD
What happens
.git/HEAD is a symbolic reference. It usually contains one line: ref: refs/heads/main. This tells git which branch is currently checked out. It is the single most important file in the entire .git directory. If HEAD is missing, empty, or points to a ref that does not exist, git does not recognize the directory as a repository at all.
iCloud's fileproviderd has been documented adding numbered suffixes to ref files during conflict resolution, creating invalid references like refs/heads/main 2. When this happens, the entire repository becomes invisible. Dropbox creates conflicted copies of HEAD itself. OneDrive syncs HEAD in a non-deterministic order relative to the refs it points to, so HEAD can arrive pointing at a branch that does not exist yet locally.
What you see
fatal: not a git repository (or any of the parent directories): .git
fatal: bad object HEAD
How to detect it
Run cat .git/HEAD. It should contain ref: refs/heads/<branch> or a 40-character SHA. If it is empty, truncated, or contains binary data, your sync service overwrote it. Check if the .git directory itself was renamed: ls -la | grep git.
Mechanism 06 Critical
Git Forgets Your Project Exists
.git/HEAD
What this means
There is one file that tells Git "this folder is a project, and here is which branch you are on." If cloud sync empties it, renames it, or deletes it, Git stops recognizing your project entirely. iCloud is especially bad about adding number suffixes to it.
What happens
This is the most confusing error because it looks like your project disappeared. Your code is still there. Git lost the one file it needs to know that it is a Git project.
Mechanism 06 Critical
HEAD Symref Single Point of Failure
.git/HEAD
Failure pattern
HEAD is a single file that tells git which branch is checked out. Every git operation reads it first. If cloud sync delivers a partial write, a conflict-renamed copy, or a zero-byte placeholder, git cannot identify the repository at all. Unlike other corruption modes where individual objects are damaged, HEAD corruption makes the entire object graph unreachable.
Observable signal
Systemic implication
Mechanism 07 High
Config File Merge Conflicts
.git/config
What happens
.git/config is a plain-text INI-style file that stores repository-level settings: remote URLs, branch tracking configuration, merge strategies, and user-defined values. When two machines modify this file (adding a remote, changing a setting) and sync, the sync service applies last-write-wins. The losing machine's changes vanish silently.
Unlike refs, the config file does not have a checksum. Git will not warn you that it changed. You will discover the problem when git push goes to the wrong remote, or when a branch tracks the wrong upstream, or when a merge strategy you configured is gone.
What you see
fatal: 'origin' does not appear to be a git repository
fatal: Could not read from remote repository.
How to detect it
Run git remote -v and verify the URLs match what you expect. Run git config --list --local and compare against your known settings. Look for conflicted copies: ls .git/config*.
Mechanism 07 High
Your Project Gets Wired to the Wrong GitHub
.git/config
What this means
Git stores the address of your GitHub project in a settings file. When cloud sync overwrites it with a version from another machine, the address can change without warning. Your next push might go to the wrong place or fail completely.
What happens
This means Git tried to connect to GitHub using the address in its settings, but that address is wrong or missing. The settings file got overwritten by cloud sync.
Mechanism 07 High
Silent Config Last-Write-Wins
.git/config
Failure pattern
Git config has no checksum, no version vector, no conflict detection. Cloud sync applies last-write-wins without signaling. Remote URLs, branch tracking, merge strategies, and credential helpers vanish or revert silently. The failure is not an error. The failure is git operating correctly against wrong configuration.
Observable signal
Systemic implication
Mechanism 08 High
Hook Permission Changes
.git/hooks/
What happens
Git hooks are executable scripts in .git/hooks/. They require the Unix executable bit (chmod +x) to run. Cloud sync services do not reliably preserve Unix file permissions. OneDrive strips the executable bit entirely. iCloud may reset permissions during sync. Google Drive's virtual filesystem (drivefs) does not support traditional permission models.
When hook permissions are stripped, git silently skips the hook. Your pre-commit linting, your commit message validation, your post-commit deployment triggers. All silently disabled. No error. No warning. The hook file exists but cannot execute.
What you see
Nothing. That is the problem. Hooks fail silently when they lack execute permissions. You discover it when your CI pipeline catches a lint error that your pre-commit hook should have caught. Or when your post-commit deployment never fires.
How to detect it
Run ls -la .git/hooks/ and verify that active hooks (files without the .sample suffix) have the x permission bit. Run find .git/hooks -type f ! -name "*.sample" ! -perm -111 to find hooks that exist but cannot execute.
Mechanism 08 High
Your Automated Scripts Stop Working and Nobody Tells You
.git/hooks/
What this means
Git can run scripts automatically before or after you save (for example, to check your code for errors). These scripts need special permission to run. Cloud sync strips that permission away, and the scripts quietly stop working.
What happens
Nothing. That is the problem. There is no error message. Your safety checks, formatters, or deploy scripts silently stop running. You will not know until something breaks downstream.
Mechanism 08 High
Hook Permission Model Mismatch
.git/hooks/
Failure pattern
Git hooks require the Unix execute bit. Cloud sync services operate on a permission-agnostic model: they preserve file contents but strip permission bits during transfer. Git does not warn when a hook exists but lacks execute permission. It silently skips it.
Observable signal
Nothing. The hook file exists but does not run. No error, no warning. Your pre-commit validation, your deployment triggers, your lint checks. All silently disabled.
Systemic implication
Mechanism 09 High
Shallow Clone Metadata Loss
.git/shallow
What happens
Shallow clones (git clone --depth=1) store a critical metadata file at .git/shallow. This file contains the SHA-1 hashes of commits that git should treat as root commits. It tells git "stop here. There is no history beyond this point." Without it, git tries to follow parent pointers that lead to objects that do not exist in the local store.
Cloud sync services treat .git/shallow as just another small text file. If it is evicted by OneDrive's Files On-Demand (replaced with a zero-byte placeholder) or if iCloud delays its sync, git loses the boundary information. The repo appears corrupted because parent references point to objects that were intentionally excluded.
What you see
error: Could not read object for refs/heads/main
fatal: bad object HEAD
How to detect it
If your repo was created with --depth, check that .git/shallow exists and is non-empty: cat .git/shallow. If it is missing or empty, run git fetch --unshallow to recover the full history from the remote.
Mechanism 09 High
Cloud Sync Throws Away Part of Your Download
.git/shallow
What this means
When you download a project, you sometimes get only recent history to save time. Git keeps a marker file that says "history stops here, do not look further back." Cloud sync can delete that marker, so Git goes looking for history that was never downloaded and panics when it cannot find it.
What happens
This means Git is trying to follow your project's history back in time but hit a gap where the history was intentionally cut short, and it no longer knows that.
Mechanism 09 High
Shallow Clone Boundary Eviction
.git/shallow
Failure pattern
The shallow file defines where the commit graph was intentionally truncated. Files On-Demand evicts it as low-priority. Without it, git traverses past the boundary, hits missing objects, and reports corruption. The graph is structurally valid but the boundary metadata that makes it interpretable is gone.
Observable signal
Systemic implication
Mechanism 10 Critical
Submodule Pointer Desync
.gitmodules + .git/modules/
What happens
Submodules are tracked by three synchronized data structures: the .gitmodules file (URL and path mappings), the parent repo's tree (commit SHA pointer), and the .git/modules/ directory (the actual submodule repo clone). All three must agree. If any one syncs out of order, the submodule is broken.
Cloud sync services treat the .git/modules/ directory as a regular folder full of regular files. Each submodule's internal .git structure is subject to the same 9 corruption mechanisms described above. But the failure is worse because the parent repo's commit tree now points to a submodule commit that the local submodule checkout cannot resolve.
What you see
fatal: repository 'path/to/submodule' not found
fatal: 'submodule' does not have a commit checked out
error: Submodule 'lib' could not be updated.
How to detect it
Run git submodule status. Any submodule prefixed with - (not initialized) or U (merge conflict) after a sync indicates desynchronization. Verify .git/modules/ exists and contains complete repos: ls .git/modules/*/HEAD.
Mechanism 10 Critical
Projects-Inside-Projects Break in Every Way at Once
.gitmodules + .git/modules/
What this means
Some projects include other projects inside them (called submodules). This requires three separate things to stay perfectly in sync. Cloud sync can break any of them, and each sub-project is also vulnerable to all nine other mechanisms on this page.
What happens
This means one of the projects inside your project has lost its connection. If you use submodules and cloud sync together, this will happen eventually.
Mechanism 10 Critical
Submodule Pointer Consistency Cascade
.gitmodules + .git/modules/
Failure pattern
Submodules require three-way consistency: .gitmodules (URL mapping), .git/modules/ (embedded repo), and the parent tree entry (pinned SHA). Cloud sync delivers these independently with no ordering guarantee. Any of the nine preceding corruption mechanisms can fire inside each submodule's embedded .git directory. Failure is multiplicative: N submodules means N+1 independent corruption surfaces.
Observable signal
Systemic implication
Full comparison matrix
Every major cloud sync service is affected. The difference is in which mechanisms hit hardest and how visible the failure is.
| Corruption Mechanism | iCloud | Dropbox | Google Drive | OneDrive |
|---|---|---|---|---|
| 1. Lockfile races | Yes | Yes | Yes | Yes |
| 2. Partial pack writes | Yes | Yes | Yes | Yes |
| 3. Index conflicts | Yes | Yes | Yes | Yes |
| 4. Ref pointer overwrites | Yes | Yes | Yes | Yes |
| 5. Loose object collisions | Yes | Yes | Partial | Yes |
| 6. HEAD symref corruption | Yes | Yes | Yes | Yes |
| 7. Config merge conflicts | Partial | Yes | Yes | Yes |
| 8. Hook permission loss | Yes | Partial | Yes | Yes |
| 9. Shallow metadata loss | Yes | Partial | Partial | Yes |
| 10. Submodule desync | Yes | Yes | Yes | Yes |
"Partial" means the service has mitigations that reduce but do not eliminate the risk. Dropbox's xattr-based ignore (manual per-folder setup required) can exclude .git directories if set manually per-folder. Google Drive for Desktop's virtual filesystem avoids some write conflicts by not keeping local copies. Neither is a complete fix.
Zero providers have issued official developer warnings. Apple, Microsoft, Google, and Dropbox have published no documentation advising developers to exclude .git directories from sync. Microsoft's WinDev issue #75, filed in January 2021, remains open and unresolved. None provide an automatic pattern-based exclusion for developer files.
What you can do about it
The simplest answer: do not put git repos in cloud-synced folders. Move your projects to a directory outside of iCloud Drive, Dropbox, Google Drive, or OneDrive. On macOS, that means outside ~/Documents and ~/Desktop if iCloud's "Desktop & Documents Folders" sync is enabled.
But that only prevents the problem. It does not give you a backup.
Pushing to GitHub or GitLab protects your committed history. It does not protect your uncommitted work, your stashes, your local branches that you have not pushed yet, or your in-progress rebases. If your machine dies, that work is gone.
This is the gap that DevSafe was built to fill. Encrypted git backups that never touch your .git directory. Never sync file-by-file. Never let a cloud daemon corrupt your repo. Your keys, your storage, your data.
But even if you never use DevSafe, the research above applies to you. Check your repos. Run git fsck. Move your projects out of synced folders. And do not trust any cloud service that cannot tell the difference between a document and a database.
The most important thing: move your projects out of cloud-synced folders. If you are on a Mac, that means moving them out of ~/Documents and ~/Desktop if iCloud sync is turned on. A good place is ~/Projects or anywhere that iCloud, Dropbox, or OneDrive does not watch.
Pushing to GitHub protects the work you have saved. But it does not protect the work you have not saved yet. If your laptop dies or your project gets corrupted, anything you had not pushed is gone.
DevSafe was built to solve this. Encrypted backups of your entire project, including unsaved work. No cloud sync touching your files. No corruption. Your keys, your storage, your data.
Even if you never use DevSafe, move your projects out of synced folders today. That one step prevents all 10 problems on this page.
Move repos out of cloud-synced directories. On macOS, ~/Documents and ~/Desktop are iCloud-synced by default. Any repo in those paths is exposed to all 10 mechanisms.
GitHub/GitLab protects committed history. It does not protect uncommitted work, stashes, unpushed branches, or in-progress rebases. If the machine fails, that state is gone.
DevSafe fills this gap: encrypted git backups that read from the object database, never touch .git, never sync file-by-file. Your keys, your storage, zero trust.
Regardless of tooling: run git fsck on any repo that has been in a cloud-synced folder. The corruption may already be present and silent.
Frequently asked questions
Why does cloud sync break git repositories?
Cloud sync treats every file as independent. Git's .git directory is a transactional database where multiple files must be written atomically. When a sync engine reads or uploads files mid-transaction, it creates inconsistent state that git cannot recover from. This is a design-level mismatch, not a bug.
What are the most common corruption errors?
fatal: Unable to create .git/index.lock (lockfile races), error: packfile does not match index (partial pack writes), fatal: bad object HEAD (ref pointer overwrites), and error: object file is empty (loose object collisions). Run git fsck --full to check.
Can any cloud sync service safely sync a git repo?
No. All four major services (iCloud, Dropbox, Google Drive, OneDrive) cause corruption through the same 10 mechanisms. Dropbox's xattr ignore and Google Drive's virtual filesystem reduce some risks but do not eliminate them. Git's own documentation warns against it.
Why does cloud sync break my project?
Cloud sync treats every file as its own thing and uploads them one at a time. But Git stores your project history as a connected system where everything has to be saved in a specific order. When cloud sync grabs files in the wrong order, or grabs a file while Git is still writing it, the whole system breaks.
Is iCloud, Dropbox, or OneDrive safe for my projects?
No. All four major cloud sync services cause the same types of corruption. None of them have fixed it. None of them warn you about it. The safest thing to do is move your projects to a folder that cloud sync does not watch.
Does pushing to GitHub protect me?
Partially. GitHub protects the work you have already pushed. But it does not protect unsaved changes, unpushed branches, or work in progress. If your project gets corrupted before you push, that work is lost.
Why is this a design mismatch, not a bug?
Cloud sync provides eventual consistency for independent files. Git requires immediate consistency across dependent files. These are incompatible consistency models. No amount of conflict resolution, retry logic, or selective sync resolves the fundamental mismatch. The failure is structural.
Does this apply to other transactional file stores?
Yes. Any application that stores state across multiple interdependent files (SQLite databases, MCP server configs, agent state directories, vector store indexes) is vulnerable to the same class of corruption under cloud sync. Git is the most documented case because its failure modes produce visible errors. Other systems may fail silently.
Have any providers shipped a structural fix?
No. Zero providers have issued developer warnings. Microsoft's WinDev issue #75, filed January 2021, remains open. None provide automatic exclusion patterns for developer files. The gap is open and unaddressed.