Git And Collaboration Workflows

Undo And Recovery

Git has several ways to undo work because uncommitted edits, local commits, published commits, and deleted branch names are different problems.

Why This Matters

Using the wrong command can discard useful work or rewrite history that teammates already use. Recovery starts by identifying which Git objects exist and whether the change has been shared.

Working Model

restore changes working-tree or index content, revert records a new inverse commit, reset moves a reference and may also change files, and the reflog records recent local reference movement. Prefer reversible operations on shared branches.

Practical Rules

  • Inspect git status, git diff, and git log --oneline --decorate before changing history.
  • Use git restore --staged to unstage without deleting the working copy.
  • Use git revert <commit> for an already-pushed change that must be undone publicly.
  • Use git reflog to locate a commit after an accidental reset or deleted local branch.
  • Create a temporary recovery branch before experimenting with uncertain history repair.

Failure Modes

  • Running reset --hard before checking whether uncommitted work exists.
  • Force-pushing a rewritten shared branch without coordination.
  • Treating reflog as a remote backup; reflogs are local and expire.
  • Reverting a merge without understanding which parent should remain.

Verification

  • Confirm the intended commit graph with git log --graph --oneline --all.
  • Check both staged and unstaged diffs.
  • Run the project checks after content is restored or reverted.
  • Fetch and compare the remote branch before pushing.

What You Should Be Able To Do

After this lesson, you should be able to explain the difference between restoring files, reverting commits, resetting references, and recovering commits through the reflog, choose a suitable approach for a real PHP project, and verify the result instead of relying on assumptions.

First Rule: Preserve The Commit Until You Understand It

Git recovery is much easier when the work still has a name. Before undoing, run git status, inspect the diff, and identify whether the work is uncommitted, staged, committed locally, pushed to a shared branch, or already merged. The safe command depends on that state.

For uncommitted changes, you can edit files, unstage with git restore --staged, discard with git restore, or temporarily save with git stash. Discarding is destructive. Use it only when you are certain the working-tree change has no value. If in doubt, create a commit or stash first so the content is recoverable.

For committed local work, prefer creating a new branch name before experimenting. A branch is cheap and gives the commit a stable pointer. If a reset or rebase goes wrong, the old branch or reflog can help recover the previous state.

Revert, Reset, Restore, And Reflog

git revert creates a new commit that undoes the effect of an earlier commit. It is usually the right tool for shared history because it preserves the record and does not require collaborators to repair their local branches. Reverting a merge commit needs extra care because Git must know which parent is the mainline.

git reset moves the current branch name. With --soft, it keeps changes staged. With mixed reset, it keeps changes in the working tree but unstaged. With --hard, it discards working-tree and index changes to match the target commit. --hard is powerful and dangerous; inspect first.

git restore is the safer modern command for restoring paths from the index or a commit. It is useful when you want to discard or recover specific files rather than move a branch.

git reflog records where local refs and HEAD have pointed. It is often the recovery path after an accidental reset, rebase, or branch deletion. Reflog is local and expires eventually, so do not treat it as a backup policy, but learn to use it before panic sets in.

Undoing Shared Work

Once a commit is pushed to a branch other people use, rewriting it becomes a collaboration problem. A force push may be acceptable on a personal review branch if the team expects rebases. It is not acceptable on main or a release branch unless the repository owners deliberately coordinate history rewriting.

Use git revert for public mistakes whenever possible. The project history then says: this change happened, it was wrong, and this commit backed it out. That audit trail matters for deployments, incident review, and other branches that may have already incorporated the commit.

If a secret was committed, reverting does not remove it from history. Rotate the credential immediately. History rewriting may reduce exposure in some repositories, but every clone, fork, cache, and CI log must be considered. The security repair is credential invalidation.

Recovering Deleted Or Misplaced Work

If a branch was deleted, check git reflog or git log --all --decorate --oneline to find the commit. Recreate a branch at that commit with git branch recovered <sha>. If work was committed on the wrong branch, branch from the current commit, then move the original branch back only after the commit is safely named elsewhere.

If a file was deleted in a commit, restore it from the commit before deletion or revert the deletion commit. Use path-specific restore when only one file should return. Avoid copying from an editor buffer because you may miss permissions, line endings, or adjacent changes.

Stash With Care

Stash is useful for temporary interruption, but it can become a drawer full of unnamed work. Give stashes messages. Apply them soon. Inspect a stash before popping it, especially if the branch has moved. git stash pop applies and drops on success; git stash apply keeps the stash for another attempt.

Do not use stash as long-term storage. A work-in-progress commit on a branch is more visible and easier to review, rebase, and recover.

Recovery Workflow

When something goes wrong, stop typing random commands. Record the current git status, copy the relevant commit IDs, and create a safety branch if a valuable commit is visible. Then decide whether you need to undo content, move a branch pointer, create a new inverse commit, or recover an old ref.

After recovery, run tests or at least inspect the diff that will be pushed. Recovery commands can restore syntax while leaving behavior inconsistent. If the mistake reached a pull request or deployment, explain the recovery path so reviewers understand the final state.

After this lesson, you should be able to choose between restore, reset, revert, stash, and reflog; recover misplaced local work; undo shared commits safely; handle secret exposure correctly; and avoid destructive commands until the work you care about has a stable name.

Recovery Drills

Git recovery should be practiced before an emergency. Create a small throwaway repository and rehearse the common cases: discard an unstaged edit, unstage a file, recover a deleted branch, undo a local commit while keeping its changes, revert a public commit, and recover from an accidental hard reset using reflog. The commands become much less frightening when the stakes are low.

During a real incident, write down the commit IDs before changing anything. If the mistake is visible on a hosting platform, capture the pull request or deployment reference too. Recovery often involves proving which version was deployed, which commit introduced the problem, and which commit reversed it. Those facts matter more than remembering the exact command you typed.

For production fixes, pair Git recovery with application recovery. Reverting code may not undo database migrations, sent emails, queued jobs, uploaded files, or external provider calls. A revert commit can restore source behavior while leaving data that needs a separate repair script. Make that distinction explicit in incident notes.

Choosing The Least Dangerous Command

When several undo commands could work, choose the one that changes the smallest scope. If only one file is wrong, restore that file rather than resetting the branch. If a public commit is wrong, revert it rather than rewriting the branch. If you need to inspect old content, create a temporary branch or use git show before moving names.

Think in terms of three questions. Am I changing file contents, staged content, or branch history? Has anyone else seen this commit? Do I need to preserve the bad state for audit? Those questions usually identify the safe command. They also help you explain the repair in a pull request.

A common PHP example is an accidental debug commit. If it is unpushed, amend or reset locally. If it is already merged, revert it and check whether logs, screenshots, or build artifacts exposed anything sensitive. If it included credentials, rotate them. Git cleanup and security cleanup are related but not identical.

Practice Exercise

In a temporary repository, create three commits, reset one locally, recover it from reflog, then revert another commit with a new commit. Compare the graph after each step. The exercise proves the difference between moving a branch name and recording an inverse change. After the exercise, explain which commands changed files and which commands changed commit history. Name the commit you would push before pushing anything.

Practice

Practice: Unstage Without Losing Work

A developer accidentally staged a configuration file together with the intended PHP change. Plan how to remove only the configuration file from the next commit.

Your answer must:

  • state the intended outcome;
  • show the commands, data flow, or implementation shape;
  • identify at least one unsafe alternative;
  • explain how the result will be verified.
Show solution

Inspect the staged diff, run git restore --staged path/to/config, and confirm the file remains modified in the working tree while disappearing from git diff --cached. Commit only the intended PHP files.

The important part is not memorising one command or vendor screen. The solution makes the invariant, failure behavior, and verification evidence explicit.

Practice: Revert A Published Change

A production regression came from a commit already merged and pulled by teammates. Design the safest undo.

Your answer must:

  • state the intended outcome;
  • show the commands, data flow, or implementation shape;
  • identify at least one unsafe alternative;
  • explain how the result will be verified.
Show solution

Create a focused branch from the current shared base, run git revert <bad-commit>, resolve conflicts if needed, run tests, and open a pull request. Do not rewrite the shared branch with reset.

The important part is not memorising one command or vendor screen. The solution makes the invariant, failure behavior, and verification evidence explicit.

Practice: Recover After Reset

A local branch was reset and an important commit no longer appears in normal log output. Recover it without guessing object IDs.

Your answer must:

  • state the intended outcome;
  • show the commands, data flow, or implementation shape;
  • identify at least one unsafe alternative;
  • explain how the result will be verified.
Show solution

Use git reflog to find the previous branch tip, inspect it with git show, create a recovery branch at that object, and compare the recovered diff before merging or cherry-picking it.

The important part is not memorising one command or vendor screen. The solution makes the invariant, failure behavior, and verification evidence explicit.