Download this page as .mdz

Using MDZip with Git, GitHub and Azure DevOps

An MDZip (.mdz) file is a ZIP archive, so Git treats it as binary. Out of the box, a pull request on GitHub or Azure DevOps shows "Binary file" where you'd expect a diff, and two branches that change the same .mdz can't be merged line by line. This page sets out a workflow that works with that instead of around it.

First: does this apply to you?

It depends on who edits the file.

  • One author, with the source of truth somewhere else. A working file: a story refined with AI and written back to Azure DevOps or GitHub, a handoff to a client, a document attached to a work item. Nobody else edits it, so there's nothing to diff or merge, and you don't need anything on this page. Commit it as a record if you like. Refine a user story with AI walks through this case.
  • Several people edit or review it in the repo. Read on.

Keep the Markdown as the source

For a document a team edits together, keep its Markdown and images as plain files in the repo, and build the .mdz when it needs to travel:

docs/
  index.md
  install.md
  images/
    architecture.svg
mdz create docs guide.mdz --title "Project guide"
mdz validate guide.mdz

Pull requests then show ordinary Markdown diffs on GitHub and Azure DevOps, merges work as they do for any text, and the .mdz is a build output, like a PDF. Don't commit it: each build writes new timestamps into the archive's manifest, so a rebuilt .mdz always looks changed. Attach it to a release or publish it from a pipeline instead, as shown below.

When the .mdz is the source

Some .mdz files are the source: written in MDZip Studio or VS Code by people who don't want a folder of Markdown files, or full of pasted screenshots. You can commit those and still review them.

Readable diffs with mdz textconv

The mdz CLI, version 2.1.0 or later, prints an archive as text for Git. Mark .mdz files in .gitattributes and commit it:

echo "*.mdz diff=mdz" >> .gitattributes

Then turn it on once in each clone. Git doesn't let a repository choose commands to run, so each person opts in:

git config diff.mdz.textconv "mdz textconv"
git config diff.mdz.cachetextconv true

Now git diff, git log -p, git show and editors' Git views show the lines that changed in each document inside the archive. An image is one line with its size and SHA-256, so a replaced picture shows up as a changed line:

 ===== index.md =====
 # Story

-- Users can reset their password
+- Users can reset their password by email
+- The link expires after 1 hour
 ===== images/login.png =====
-[binary, 48211 bytes, sha256 9f2c…]
+[binary, 51007 bytes, sha256 1ab4…]

A clone without the setting still works and shows "Binary files differ", as before.

Comparing in VS Code

The VS Code extension compares what's inside an .mdz without any Git setup. MDZip: Compare Document Markdown with Git Base shows the document's changes since the last commit, and MDZip: Compare Archive Contents with Git Base lists every file inside the archive that was added, removed or changed.

What still doesn't work

  • Diffs on the web. GitHub and Azure DevOps don't run textconv, so their pull request pages still show an .mdz as binary. Reviewers diff the branch locally, use the VS Code commands, or read the diff a pipeline prints (see the GitHub Actions example below).
  • Merges. Two branches that change the same .mdz still conflict, and Git can't combine them. Keep one version and redo the other change on top of it, or have one person edit each .mdz at a time. A merge driver is proposed in mdzip-cli#14.

If a document gets edited by several people at once, that's a sign it belongs in the repo as Markdown, as above.

Checking and packaging in CI

GitHub Actions

setup-mdz installs mdz on Linux, macOS and Windows runners. This workflow checks every .mdz in a pull request and prints what changed inside them in the job log:

name: Check .mdz files
on: pull_request
jobs:
  check:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v5
        with:
          fetch-depth: 0
      - uses: mdzip-project/setup-mdz@v1
        with:
          version: 2.1.0
      - name: Validate
        shell: bash
        run: |
          shopt -s globstar nullglob
          for f in **/*.mdz; do mdz validate "$f"; done
      - name: Show what changed inside them
        run: |
          git config diff.mdz.textconv "mdz textconv"
          echo "*.mdz diff=mdz" >> .git/info/attributes
          git diff "origin/${{ github.base_ref }}" -- '*.mdz'

To build an .mdz from a docs folder and attach it to each release, see the setup-mdz examples.

Azure Pipelines

On Azure Pipelines, install mdz with its install script, then use it like any other command. This pipeline builds the .mdz from docs/, checks it, and publishes it as a pipeline artifact:

trigger:
  - main

pool:
  vmImage: ubuntu-latest

steps:
  - script: |
      curl -fsSL https://raw.githubusercontent.com/mdzip-project/mdzip-cli/main/scripts/install.sh | MDZ_VERSION=v2.1.0 sh
      echo "##vso[task.prependpath]$HOME/.local/bin"
    displayName: Install mdz

  - script: |
      mdz create docs "$(Build.ArtifactStagingDirectory)/guide.mdz" --title "Project guide"
      mdz validate "$(Build.ArtifactStagingDirectory)/guide.mdz"
    displayName: Package the docs

  - publish: $(Build.ArtifactStagingDirectory)
    artifact: docs

MDZ_VERSION pins the release, so a new one can't change your builds without you knowing. Read the install script before you use it, as with any script run from a URL. To check committed .mdz files in a pull request build, run the same mdz validate loop as in the GitHub Actions example.

Publishing from .mdz files

  • mdzip-pandoc converts an .mdz to HTML, Word, EPUB or PDF with Pandoc, on your machine or as a GitHub Action.
  • mdzip-pages-example is a template for a website whose pages are .mdz files. On every push, GitHub checks the pages, converts them to HTML and publishes them on GitHub Pages. See it live.

Attaching to work items and issues

An .mdz carries a whole document, pictures included, in one attachment.

  • Azure DevOps: attach it to a work item like any other file. Anyone can open it in MDZip Studio, VS Code or the web editor, with nothing to install for the last.
  • GitHub: issues and pull request comments accept only some file types. If GitHub refuses an .mdz, add .zip to its name (story.mdz.zip). It's a ZIP file, so it opens either way, and the reader can rename it back.

More

This page renders from git.mdz (MDZip, ~5 KB, updated 2026-11-12) — one self-contained file. Download it, open it in the web editor, or read how these pages are made.