Git keeps a history of the files you have committed. If someone changes a live website file such as index.php, you can use Git to compare the live file with a known version, inspect older versions, and restore a clean copy. Commands such as git status show which files changed, while git diff shows the exact changes. After verifying that a committed version is clean, git checkout or git restore can put that version back.
In my Laravel website incident, the homepage showed a gambling page because the live index.php had been changed. The version stored in Git was clean, so restoring index.php helped bring back the normal homepage. Git helped recover the file; it did not explain how the change happened or secure the server. Those require a separate investigation and security fixes.
Keeps file history: Git stores versions of files that were committed. You can inspect an earlier index.php if that version exists in the repository.
Shows which tracked files changed: git status --short helps you spot modified or deleted files. It also lists untracked files, such as an unexpected blog/index.html.
Shows the exact changes: git diff -- index.php compares the working file with Git’s staged version. This can reveal injected content. Use git diff --cached -- index.php to check changes that were already staged.
Helps you find a known good version: git log --oneline --follow -- index.php lists earlier commits affecting the file. git show :index.php lets you read an older version without changing the live website.
Restores one file: After verifying the Git version is clean, git checkout -- index.php can replace the changed working file. You can also use git restore to select a particular older commit.
Can reverse a bad commit: If the unwanted change was committed, git revert creates another commit that reverses it while keeping the history.
Can help after an accidental reset: git reflog shows where the local branch pointed recently, which may help you find a lost commit. It cannot recover every overwritten, uncommitted change.
What Happened on My Laravel Website
- Visitors saw a gambling page because the live index.php had been changed.
- The version of index.php stored in Git was clean.
- Restoring the file with git checkout -- index.php .htaccess helped bring back the normal homepage.
- Git restored those tracked files, but any separate untracked suspicious file needed its own investigation.
- Restoring the homepage did not reveal how the files were changed or secure the server. I still needed to investigate the entry point, check other files, and address the reported public access to .env. Before replacing a suspicious file, save a copy outside the web directory. Its contents and timestamps may be useful during the investigation.
How to Restore a Changed File with git checkout
How to Restore a Changed File with git checkout
website-hacking-seo-spamincident-response
Use of Different Git command
git status --short — see which files changed
git status --short
Before: index.php and .htaccess were changed; an extra file appeared.
M index.php
M .htaccess
?? blog/index.html
M means modified. ?? means untracked: Git has no committed copy of that file.
After: This command changes nothing. Running it again gives the same output.
- git diff -- index.php .htaccess — see what changed
git diff -- index.php .htaccess
Before: Git’s index.php starts Laravel, but the working file contains spam.
Example output:
diff --git a/index.php b/index.php
--- a/index.php
+++ b/index.php
@@
-<?php require __DIR__.'/vendor/autoload.php';
+<html><title>CERUTU4D</title>...</html>
After: No files change. The diff still appears if you run it again.
This shows unstaged changes. If git status --short shows M with the M in the first column, inspect staged changes too:
git diff --cached -- index.php .htaccess
3.** git log --oneline --follow -- index.php — find earlier commits**
git log --oneline --follow -- index.php
Example output:
a81c390 Update Laravel entry point
74b2e10 Fix bootstrap path
31d9f42 Initial homepage
After: Nothing changes. You now have commit hashes to inspect. --follow also helps trace the file across a rename.
- git show :index.php — read an old version
git show 74b2e10:index.php
Example output:
<?php
require __DIR__.'/vendor/autoload.php';
$app = require_once __DIR__.'/bootstrap/app.php';
Before and after: Your live index.php stays exactly as it was. This is a good way to check whether commit 74b2e10 has the version you actually want.
- git checkout -- index.php .htaccess — restore the current staged versions
git checkout -- index.php .htaccess
Before:
Working index.php: gambling page
Git index.php: clean Laravel entry point
Command output: Usually none.
After:
Working index.php: clean Laravel entry point
Git index.php: clean Laravel entry point
Check the result:
git status --short
?? blog/index.html
The modifications to index.php and .htaccess are gone. The untracked blog/index.html is still there. This is why your homepage could recover while a separate suspicious file remained.
Technically, git checkout -- file copies from Git’s index (staging area). If someone staged a malicious version first, this command could copy that version. Inspect staged changes when that is possible.
- git restore --source= --worktree -- index.php — recover an older file without staging it Suppose the current committed homepage is broken, and you verified that 74b2e10 has the clean version:
git restore --source=74b2e10 --worktree -- index.php
Before:
HEAD index.php: broken newer version
Working index.php: broken newer version
Command output: Usually none.
After:
HEAD index.php: broken newer version
Working index.php: clean version from 74b2e10
git status --short
M index.php
The leading space before M means the recovered file is changed in your working tree but not staged. You can review it with git diff -- index.php.
- git checkout -- index.php — recover an older file and stage it
git checkout 74b2e10 -- index.php
Before: The working file and staged version contain the newer version.
Command output: Usually none.
After:
git status --short
M index.php
Here M is in the first column: the older file is already staged. Check what would go into a commit with:
git diff --cached -- index.php
That staging behavior is the key difference from the git restore --worktree example above.
- git revert — reverse a bad committed change Suppose commit c52f901 introduced an unwanted homepage change: git revert c52f901
Before:
c52f901 Add unwanted homepage change
a81c390 Previous good commit
Example output:
[main e63a104] Revert "Add unwanted homepage change"
1 file changed, 1 insertion(+), 1 deletion(-)
After:
e63a104 Revert "Add unwanted homepage change"
c52f901 Add unwanted homepage change
a81c390 Previous good commit
Git keeps the bad commit in history and adds a new commit that reverses it. A revert can require conflict resolution if later commits changed the same lines.
- git reflog — find where your branch pointed before a reset Suppose someone ran git reset --hard and you need to find the previous commit: git reflog
Example output:
74b2e10 HEAD@{0}: reset: moving to 74b2e10
a81c390 HEAD@{1}: commit: Update Laravel entry point
Before and after: git reflog changes nothing. It tells you that this local repository previously pointed at a81c390. You can inspect it first:
git show --stat a81c390
A reflog may help recover committed work after a reset. It cannot bring back an uncommitted file overwritten by reset --hard, and its entries do not last forever.
For your actual incident: start with status, both diff commands, log, and show; preserve suspicious files; then restore only the verified files you need. git reset --hard affects the whole tracked working tree, so it is a poor first response to one changed homepage file.
Compare a File’s Historical Versions Using Commit IDs
Step 1: Find commits that changed the file
git log --oneline --follow -- resources/views/home.blade.php
Example output:
e4f5a6b Update homepage banner
a1b2c3d Add homepage
Suppose a1b2c3d is the older version and e4f5a6b is the newer version.
Step 2: See the content difference
git diff a1b2c3d e4f5a6b -- resources/views/home.blade.php
Example output:
-<h1>Explore HolidayLandmark</h1>
+<h1>Find Your Next Trip</h1>
The - line is from the older version. The + line is from the newer version.
Step 3: Read either complete version
git show a1b2c3d:resources/views/home.blade.php
git show e4f5a6b:resources/views/home.blade.php
Example output from the first command:
Explore HolidayLandmark
Example output from the second command:
Find Your Next Trip
Before and after: The live resources/views/home.blade.php is untouched.
git log --follow helps find history across a rename, but git show needs the path that existed in the chosen commit. If the file had a different name then, use its old path for the old commit.
Another Example
Using 28 July 2026 and 21 September 2026 as examples (two months and one week before 28 September)
- Find the last commit available on each date Run these from the correct Git repository:
git log -1 --before="2026-07-29 00:00:00" --format="%h %ci %s" HEAD
git log -1 --before="2026-09-22 00:00:00" --format="%h %ci %s" HEAD
Example output:
a1b2c3d 2026-07-27 16:20:00 +0530 Update homepage
e4f5a6b 2026-09-21 18:45:00 +0530 Update booking page
Here, a1b2c3d is the July snapshot and e4f5a6b is the September snapshot. The first commit may be dated July 27 because there was no commit on July 28.
- See which files differ between those snapshots
git diff --name-status a1b2c3d e4f5a6b
Example output:
M index.php
M .htaccess
A resources/views/trips/show.blade.php
D old-home.html
M = modified, A = added, D = deleted. This answers: “Which committed files were different one week ago compared with two months ago?”
- See the actual content differences For all those files:
git diff a1b2c3d e4f5a6b
For only index.php:
git diff a1b2c3d e4f5a6b -- index.php
Example output:
-<?php require __DIR__.'/vendor/autoload.php';
+<?php require __DIR__.'/new-bootstrap.php';
A line beginning with - existed in the July version; a line beginning with + existed in the September version. These commands only display differences; they do not change your files.
- If you mean “what was changed during each period” That is a different question from comparing two snapshots. List commits and their files for each date range:
git log --since="2026-07-28 00:00:00" --until="2026-07-29 00:00:00" --name-status --oneline
git log --since="2026-09-21 00:00:00" --until="2026-09-22 00:00:00" --name-status --oneline
These show changes committed during July 28 and September 21, respectively. If no commits occurred on a date, the output will be empty.
Important for your hack investigation: Git’s historical commands show committed history. If someone directly edited the live index.php without committing it, that edit will not appear in a July-to-September commit comparison. Compare the current live working file against the selected commit with:
git diff e4f5a6b -- index.php
Another EXAMPLE
ou can give Git the dates and let it find the commits automatically. To compare index.php as it stood about two months ago (28 July 2026) with one week ago (21 September 2026), run this inside the repository:
OLD=$(git rev-list -1 --before="2026-07-29 00:00:00 +0530" HEAD)
NEW=$(git rev-list -1 --before="2026-09-22 00:00:00 +0530" HEAD)
git diff "$OLD" "$NEW" -- index.php
The dates use the start of the following day, so Git picks the latest commit available by the end of July 28 and September 21. You do not need to look up or type a commit ID yourself.
Example output:
-<?php require __DIR__.'/vendor/autoload.php';
+<?php require __DIR__.'/bootstrap/new-autoload.php';
- is the line in the two-month-old version; + is the line in the one-week-old version. To see each complete file instead of just the difference:
git show "$OLD:index.php"
git show "$NEW:index.php"
These commands only read Git history; they do not change your live file. They can show a version only if it was committed. If the attacker changed the live index.php without making a commit, compare that live file separately with git diff HEAD -- index.php.
Compare a File’s Historical Versions by Date Without Knowing Commit IDs
Step 1: Let Git find a commit for each date
Run these lines in the same terminal, from the repository directory:
OLD=$(git rev-list -1 --before="2026-07-29 00:00:00 +0530" HEAD)
NEW=$(git rev-list -1 --before="2026-09-22 00:00:00 +0530" HEAD)
The commands normally print nothing. OLD now holds the latest reachable commit available by the end of 28 July; NEW does the same for 21 September.
Check that both were found:
echo "$OLD"
echo "$NEW"
Example output:
a1b2c3d9...
e4f5a6b8...
If either line is empty, stop: Git did not find a commit before that date on the current history.
Step 2: Compare the Blade file
git diff "$OLD" "$NEW" -- resources/views/home.blade.php
Example output:
-<h1>Explore HolidayLandmark</h1>
+<h1>Find Your Next Trip</h1>
Step 3: Read the complete file at each date
git show "$OLD:resources/views/home.blade.php"
git show "$NEW:resources/views/home.blade.php"
Before and after: The live Blade file is untouched. Git displayed versions from committed history. If an attacker edited the live file without committing, compare that current file separately:
git diff HEAD -- resources/views/home.blade.php
Another Example to compare a File’s Historical Versions by Date Without Knowing Commit IDs
OLD=$(git rev-list -1 --before="2026-07-29 00:00:00 +0530" HEAD)
NEW=$(git rev-list -1 --before="2026-09-22 00:00:00 +0530" HEAD)
git diff "$OLD" "$NEW" -- index.php
Run them in the same terminal session, from the Git repository directory. OLD and NEW temporarily hold the commit IDs Git found. The first two lines normally print nothing; the third shows the content difference.
To check what Git found before comparing:
echo "$OLD"
echo "$NEW"
If either prints an empty line, Gi
Another Example to compare a File’s Historical Versions by Date Without Knowing Commit IDs
OLD=$(git rev-list -1 --before="2026-07-29 00:00:00 +0530" HEAD)
NEW=$(git rev-list -1 --before="2026-09-22 00:00:00 +0530" HEAD)
git diff "$OLD" "$NEW" -- resources/views/home.blade.php
That shows what changed in the Blade file between the two dates. To read the complete version from each date:
git show "$OLD:resources/views/home.blade.php"
git show "$NEW:resources/views/home.blade.php"
For example, if your actual path is resources/views/trips/show.blade.php, substitute that full relative path in all three commands. If Git reports that the path does not exist in the older commit, the file may have been created or renamed after that date
website-hacking-seo-spamincident-response
root-domain-serving-the-blog-instead-of-your-laravel






Top comments (0)