How to version-control your MU Online server configuration with Git
Learn why and how to version-control your MU Online server settings with Git, what to include, what you must never commit, and how to roll back changes safely.
Every MU Online server administrator has lived through this scene: the server was perfect yesterday, someone tweaked a drop value, changed an experience rate or edited a line in the GameServer configuration, and today something is broken — but nobody remembers exactly what changed. Without a record
Every MU Online server administrator has lived through this scene: the server was perfect yesterday, someone tweaked a drop value, changed an experience rate or edited a line in the GameServer configuration, and today something is broken — but nobody remembers exactly what changed. Without a record of changes, the only way out is to hunt the problem in the dark, comparing files from memory or restoring an entire backup and losing everything that came after. Version-controlling the configuration with Git solves this problem at the root. Git is a version-control system that keeps the complete history of every text file: who changed it, when, exactly what was altered, and it lets you return to any earlier point with surgical precision. For a MU server, where dozens of .ini, .txt and .dat configuration files govern how the game behaves, that is pure gold. This tutorial shows why to version-control, what to put in the repository and — just as important — what to never put in it, how to set up a proper .gitignore, how to use a private repository and how to roll back changes with confidence. The file names and formats cited here are examples and vary by emulator/version, but the method is universal.
Why version-control the configuration
Version control isn't a programmer's fussy habit. For a MU server, it delivers concrete benefits:
- Traceability: every change is logged with author, date and description. You know exactly when the experience rate was changed and why.
- Precise rollback: instead of restoring an entire backup, you undo only the problematic change, preserving everything else.
- Comparison (diff): before applying, you see line by line what will change. This catches typos and absurd values before they go live.
- Safe collaboration: if your team has more than one administrator, Git prevents one from overwriting another's work without noticing.
- Living documentation: the commit history becomes a diary of the server, telling the story of how balancing decisions evolved.
Without version control, the server's "memory" lives in the head of whoever administers it — and disappears when that person forgets or leaves. With Git, the memory belongs to the project.
Prerequisites
- Git installed on the machine (download it from git-scm.com; on Windows it comes with Git Bash, which is handy too).
- Access to the server folder where the configuration files live.
- An account with a private-repository provider (GitHub, GitLab or Bitbucket) — all of them offer free private repositories.
- Basic command-line familiarity (opening a terminal in the folder and typing commands).
- A text editor to create the
.gitignorefile.
You don't need to know how to program. The set of commands used here is small and repetitive. If you've already set up a server following a guide on how to create a MU Online server, the Git learning curve will be gentle.
What to version-control and what NOT to
This is the most important decision in the whole process. Putting the wrong thing in Git causes everything from bloated repositories to data leaks.
| Version-control (YES) | Do not version-control (NO) |
|---|---|
.ini, .txt, .xml configuration files | The database and its .mdf/.ldf files |
| Deploy and maintenance scripts | Large binaries (the emulator's .exe, .dll) |
| Drop, event and rate configuration | Server logs |
| Balancing files (monsters, items) | Passwords, tokens, connection strings with passwords |
Documentation and runbooks (.md) | Dumps, .bak backups, temporary files |
The .gitignore itself | Player and account data |
The mental rule: Git is for text configuration that changes by human decision, not for operational data that changes on its own. The database is the classic example of what not to version-control — it changes on every login, on every dropped item, every second of gameplay. Trying to version-control it fills the repository with noise and also puts sensitive account data at risk. The database has its own backup cycle in SQL Server, separate from Git.
Binaries are also left out for another reason: Git is optimized for text. It stores efficient diffs of text files, but treats each version of an .exe as a whole new blob, bloating the repository quickly. If you do need to version-control large binaries, there are specific extensions for that, but for pure configuration they're unnecessary.
Step 1 — Initialize the repository
Open a terminal in the server's configuration folder. Ideally you version-control a folder that contains the config files, not the entire root with its binaries.
cd D:/MuServer/Config
git init
git config user.name "Your Name"
git config user.email "[email protected]"
git init creates a hidden .git subdirectory that will hold the entire history. From here on, that folder is a repository. The two config lines identify who makes the commits — important when there's more than one administrator.
Step 2 — Create the .gitignore BEFORE the first commit
This step comes before adding any file, and that's deliberate. The .gitignore is a list of patterns that Git should ignore. Creating it first stops you from accidentally committing something sensitive right at the start.
# Database - NEVER version-control
*.mdf
*.ldf
*.bak
*.bacpac
# Emulator binaries
*.exe
*.dll
*.pdb
# Logs
*.log
logs/
Logs/
# Secrets and credentials
*secret*
*.key
connection.config
credentials.ini
# Temporary files
*.tmp
*.bak
Thumbs.db
desktop.ini
Adjust the patterns to your emulator's structure. If the database connection passwords live inside a config file that you need to version-control, the solution is to extract the secret into a separate (ignored) file and keep only an example template in the repository, such as connection.example.ini, without the real password. Where the credentials are stored varies by emulator/version.
Step 3 — First commit
With the .gitignore in place, add the files and make the initial commit.
git add .
git status # check what WILL be committed BEFORE confirming
git commit -m "Initial server configuration"
Running git status before the commit is a golden habit. It lists everything that will go into the commit. Stop and read that list. If any .mdf, .log or password-bearing file shows up, your .gitignore is incomplete — fix it before confirming. A secret that lands in the first commit stays in history forever, even if you delete it later.
Step 4 — Day-to-day workflow
The version-control routine is a short cycle that repeats with every change:
- Before you touch anything, make sure everything is committed (a clean
git status). - Make the configuration change (adjust a rate, a drop, etc.).
- See exactly what changed with
git diff. - Add and commit with a descriptive message.
git diff # review the changes line by line
git add config_drops.ini
git commit -m "Raise excellent drop rate for weekend events"
The quality of the commit message determines how useful the history is. "tweaks" helps nobody; "Reduce EXP from 500x to 400x after balancing complaints" tells a story you'll understand months later. Commit small, cohesive changes instead of big bundles — that way, reverting one of them doesn't undo the others.
Step 5 — Private remote repository
A repository only on your machine protects against mistakes, but not against the machine catching fire. Push the history to a private remote.
git remote add origin [email protected]:your-user/mu-config.git
git branch -M main
git push -u origin main
I insist on private: the settings reveal ports, internal structure and details that make attacks easier, plus any secrets that slipped past the .gitignore. GitHub, GitLab and Bitbucket offer free private repositories — there's no reason to go public here. Prefer SSH-key authentication or a personal access token over a password.
Step 6 — Consult the history
Git's value shows up when you need to understand the past.
git log --oneline --graph # compact view of all commits
git log -p config_drops.ini # full history of ONE file
git show <hash> # detail of a specific commit
git blame config_exp.ini # who changed each line and when
git log -p <file> is especially useful in MU: want to know every time the EXP rate was touched? This command shows every change to that file, with date and author. git blame answers "who put this value here?" line by line.
Step 7 — Roll back changes safely
Here's the payoff for all the effort. There are several ways to go back, each for a different situation.
| Situation | Command | What it does |
|---|---|---|
| Discard an uncommitted change | git checkout -- file.ini | Returns the file to the last commit |
| Recover an old version of a file | git checkout <hash> -- file.ini | Brings that file back from a past commit |
| Undo a bad commit while keeping history | git revert <hash> | Creates a new commit that cancels the previous one |
| Return the whole repository to a point | git reset --hard <hash> | Discards everything after the hash (careful) |
For production, prefer git revert over git reset --hard. revert creates a new commit that undoes the problematic one, preserving history — everyone can see that a reversal happened and why. reset --hard erases the later history and, if it was already pushed to the remote, causes conflicts for the team. Use reset --hard only on local changes that haven't been shared yet.
A practical example: you changed the drop rate, published it, and the server's economy went haywire. To go back:
git log --oneline # find the hash of the drop-change commit
git revert a1b2c3d # cancel that specific change
git push # send the reversal to the remote
Notice that you undid only the drop change, without touching anything else adjusted afterward. That's impossible with a whole-folder backup.
Best practices for messages and organization
- Write messages in the imperative and be specific: "Fix ConnectServer port", not "changed the config".
- Commit one logical change at a time; avoid the "giant" commit that mixes ten different tweaks.
- Use a separate branch for balancing experiments and only merge once validated.
- Tag stable versions (
git tag -a v1.0 -m "Stable server post-launch") so you can find them later. - Always review with
git diffandgit statusbefore committing. Blind confirmation is the source of nearly every Git accident.
Common errors and fixes
| Symptom | Likely cause | Fix |
|---|---|---|
| Huge, slow repository | Binaries or .bak files were committed | Reinforce the .gitignore and remove them from history via a rewrite |
| Password exposed in the repository | A secret got into a commit | Change the password NOW; then remove it from history |
.gitignore has no effect | The file was already tracked before the rule | Use git rm --cached file and commit |
| Database in the repository | .mdf/.ldf not ignored | Never version-control the database; remove it and add it to the ignore list |
| Conflict on push | Local history diverged from the remote | Run git pull and resolve before push |
| Reset wiped out the team's work | Used reset --hard on a shared branch | Prefer git revert on already-published code |
| I don't know who changed a value | No habit of small commits | Adopt atomic commits with good messages |
Launch checklist
- Git installed and
user.name/user.emailconfigured .gitignorecreated BEFORE the first commit- Database, binaries and logs listed in the
.gitignore - No password or connection string version-controlled
- Secrets extracted into an ignored file, with an example template in the repo
git statusreviewed before every commit- First commit made and checked
- Remote repository created as PRIVATE
- SSH-key or token authentication set up
- Team aligned on using
revertinstead ofreset --hardon shared code - Descriptive commit messages have become a habit
- Database backup kept on a routine separate from Git
Version-controlling the configuration with Git turns server administration from an exercise in fragile memory into a process with a complete history and precise rollback. The investment is small — half a dozen commands and the discipline of keeping secrets and data out of the repository — and the return shows up the first time you need to undo a change without losing everything that came after. Start today by version-controlling the config folder, make small and frequent commits, and treat the .gitignore as your line of defense against leaks. Adapt the file names to your emulator's reality, because those details always vary by emulator/version.
Frequently asked questions
Should I version-control the server database in Git?
No. The database changes every second while the game is running and holds sensitive account data. Git is for configuration and scripts, not for operational data. The database needs its own backup routine through SQL Server.
Can I use a public GitHub repository?
Not recommended. A server's settings expose ports, internal structure and, if you're not careful, passwords. Always use a private repository, and even then keep credentials out of version control.
Does Git replace my backup system?
No. Git version-controls configuration text and change history, but it is not a backup for large binaries or for the database. It complements your backup strategy; it doesn't replace it.
What do I do if I committed a password by mistake?
Change the password immediately, because it must be treated as compromised. Then remove the secret from history with history-rewriting tools, but treat rotating the credential as the top-priority action.
Do I need to know how to program to use Git?
No. To version-control configuration you use a handful of commands: init, add, commit, log and checkout. It's a short learning curve and the gain in traceability pays off many times over.