mirror of
https://github.com/borgbackup/borg.git
synced 2026-09-01 14:13:19 +02:00
287 lines
9.7 KiB
Groff
287 lines
9.7 KiB
Groff
.\" Man page generated from reStructuredText
|
|
.\" by the Docutils 0.22.4 manpage writer.
|
|
.
|
|
.
|
|
.nr rst2man-indent-level 0
|
|
.
|
|
.de1 rstReportMargin
|
|
\\$1 \\n[an-margin]
|
|
level \\n[rst2man-indent-level]
|
|
level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
|
|
-
|
|
\\n[rst2man-indent0]
|
|
\\n[rst2man-indent1]
|
|
\\n[rst2man-indent2]
|
|
..
|
|
.de1 INDENT
|
|
.\" .rstReportMargin pre:
|
|
. RS \\$1
|
|
. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin]
|
|
. nr rst2man-indent-level +1
|
|
.\" .rstReportMargin post:
|
|
..
|
|
.de UNINDENT
|
|
. RE
|
|
.\" indent \\n[an-margin]
|
|
.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]]
|
|
.nr rst2man-indent-level -1
|
|
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
|
|
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
|
|
..
|
|
.TH "borg-diff" "1" "2026-08-29" "" "borg backup tool"
|
|
.SH Name
|
|
borg-diff \- Finds differences between two archives.
|
|
.SH SYNOPSIS
|
|
.sp
|
|
borg [common options] diff [options] ARCHIVE1 ARCHIVE2 [PATH...]
|
|
.SH DESCRIPTION
|
|
.sp
|
|
This command finds differences (file contents, metadata) between ARCHIVE1 and ARCHIVE2.
|
|
.sp
|
|
For more help on include/exclude patterns, see the output of the \fIborg_patterns\fP command.
|
|
.SH OPTIONS
|
|
.sp
|
|
See \fIborg\-common(1)\fP for common options of Borg commands.
|
|
.SS arguments
|
|
.INDENT 0.0
|
|
.TP
|
|
.B ARCHIVE1
|
|
ARCHIVE1 name
|
|
.TP
|
|
.B ARCHIVE2
|
|
ARCHIVE2 name
|
|
.TP
|
|
.B PATH
|
|
paths of items inside the archives to compare; patterns are supported.
|
|
.UNINDENT
|
|
.SS options
|
|
.INDENT 0.0
|
|
.TP
|
|
.B \-\-numeric\-ids
|
|
only consider numeric user and group identifiers
|
|
.TP
|
|
.B \-\-same\-chunker\-params
|
|
override the check of chunker parameters
|
|
.TP
|
|
.BI \-\-format \ FORMAT
|
|
specify format for differences between archives (default: \(dq{change} {path}{NL}\(dq)
|
|
.TP
|
|
.B \-\-json\-lines
|
|
Format output as JSON Lines.
|
|
.TP
|
|
.B \-\-sort\-by
|
|
Sort output by comma\-separated fields (e.g., \(aq>size_added,path\(aq).
|
|
.TP
|
|
.B \-\-content\-only
|
|
Only compare differences in content (exclude metadata differences)
|
|
.UNINDENT
|
|
.SS Include/Exclude options
|
|
.INDENT 0.0
|
|
.TP
|
|
.BI \-e \ PATTERN\fR,\fB \ \-\-exclude \ PATTERN
|
|
exclude paths matching PATTERN
|
|
.TP
|
|
.BI \-\-exclude\-from \ EXCLUDEFILE
|
|
read exclude patterns from EXCLUDEFILE, one per line
|
|
.TP
|
|
.BI \-\-pattern \ PATTERN
|
|
include/exclude paths matching PATTERN
|
|
.TP
|
|
.BI \-\-patterns\-from \ PATTERNFILE
|
|
read include/exclude patterns from PATTERNFILE, one per line
|
|
.UNINDENT
|
|
.SH EXAMPLES
|
|
.INDENT 0.0
|
|
.INDENT 3.5
|
|
.sp
|
|
.EX
|
|
# By default, borg diff reports metadata changes (mode, mtime, ctime, ...) besides
|
|
# the content changes, so the lines can get quite long:
|
|
$ borg diff archive1 archive2
|
|
[mtime: Fri, 2026\-08\-28 12:26:23.433047048 +0200 \-> Fri, 2026\-08\-28 12:26:24.204040020 +0200] [ctime: Fri, 2026\-08\-28 12:26:23.433047048 +0200 \-> Fri, 2026\-08\-28 12:26:24.204040020 +0200] .
|
|
modified: +17 B \-5 B [\-rw\-r\-\-r\-\- \-> \-rwxr\-xr\-x] [mtime: Fri, 2026\-08\-28 12:26:23.431245244 +0200 \-> Fri, 2026\-08\-28 12:26:24.199251801 +0200] [ctime: Fri, 2026\-08\-28 12:26:23.431245244 +0200 \-> Fri, 2026\-08\-28 12:26:24.200688313 +0200] file1
|
|
modified: +135 B \-252 B [mtime: Fri, 2026\-08\-28 12:26:23.432895166 +0200 \-> Fri, 2026\-08\-28 12:26:24.202236091 +0200] [ctime: Fri, 2026\-08\-28 12:26:23.432895166 +0200 \-> Fri, 2026\-08\-28 12:26:24.202236091 +0200] file2
|
|
added: 0 B file4
|
|
removed: 0 B file3
|
|
|
|
# \-\-content\-only hides the metadata changes and only reports content differences:
|
|
$ borg diff \-\-content\-only archive1 archive2
|
|
modified: +17 B \-5 B file1
|
|
modified: +135 B \-252 B file2
|
|
added: 0 B file4
|
|
removed: 0 B file3
|
|
|
|
# Use \-\-json\-lines to get one JSON object per changed path:
|
|
$ borg diff \-\-json\-lines \-\-content\-only archive1 archive2
|
|
{\(dqchanges\(dq: [{\(dqadded\(dq: 17, \(dqremoved\(dq: 5, \(dqtype\(dq: \(dqmodified\(dq}], \(dqpath\(dq: \(dqfile1\(dq}
|
|
{\(dqchanges\(dq: [{\(dqadded\(dq: 135, \(dqremoved\(dq: 252, \(dqtype\(dq: \(dqmodified\(dq}], \(dqpath\(dq: \(dqfile2\(dq}
|
|
{\(dqchanges\(dq: [{\(dqadded\(dq: 0, \(dqremoved\(dq: 0, \(dqtype\(dq: \(dqadded\(dq}], \(dqpath\(dq: \(dqfile4\(dq}
|
|
{\(dqchanges\(dq: [{\(dqadded\(dq: 0, \(dqremoved\(dq: 0, \(dqtype\(dq: \(dqremoved\(dq}], \(dqpath\(dq: \(dqfile3\(dq}
|
|
|
|
# Use \-\-sort\-by with a comma\-separated list; sorts apply stably from last to first.
|
|
# Here: primary by net size change descending, tie\-breaker by path ascending
|
|
$ borg diff \-\-content\-only \-\-sort\-by=\(dq>size_diff,path\(dq archive1 archive2
|
|
modified: +17 B \-5 B file1
|
|
removed: 0 B file3
|
|
added: 0 B file4
|
|
modified: +135 B \-252 B file2
|
|
.EE
|
|
.UNINDENT
|
|
.UNINDENT
|
|
.SH NOTES
|
|
.SS The FORMAT specifier syntax
|
|
.sp
|
|
The \fB\-\-format\fP option uses Python\(aqs format string syntax \%<https://\:docs\:.python\:.org/\:3\:.11/\:library/\:string\:.html#\:formatstrings>\&.
|
|
.sp
|
|
Examples:
|
|
.INDENT 0.0
|
|
.INDENT 3.5
|
|
.sp
|
|
.EX
|
|
$ borg diff \-\-format \(aq{content:30} {path}{NL}\(aq ArchiveFoo ArchiveBar
|
|
modified: +4.1 kB \-1.0 kB file\-diff
|
|
\&...
|
|
|
|
# {VAR:<NUMBER} \- pad to NUMBER columns left\-aligned.
|
|
# {VAR:>NUMBER} \- pad to NUMBER columns right\-aligned.
|
|
$ borg diff \-\-format \(aq{content:>30} {path}{NL}\(aq ArchiveFoo ArchiveBar
|
|
modified: +4.1 kB \-1.0 kB file\-diff
|
|
\&...
|
|
.EE
|
|
.UNINDENT
|
|
.UNINDENT
|
|
.sp
|
|
The following keys are always available:
|
|
.INDENT 0.0
|
|
.IP \(bu 2
|
|
NEWLINE: OS dependent line separator
|
|
.IP \(bu 2
|
|
NL: alias of NEWLINE
|
|
.IP \(bu 2
|
|
NUL: NUL character for creating print0 / xargs \-0 like output
|
|
.IP \(bu 2
|
|
SPACE: space character
|
|
.IP \(bu 2
|
|
TAB: tab character
|
|
.IP \(bu 2
|
|
CR: carriage return character
|
|
.IP \(bu 2
|
|
LF: line feed character
|
|
.UNINDENT
|
|
.sp
|
|
Keys available only when showing differences between archives:
|
|
.INDENT 0.0
|
|
.IP \(bu 2
|
|
path: archived file path
|
|
.IP \(bu 2
|
|
change: all available changes
|
|
.IP \(bu 2
|
|
content: file content change
|
|
.IP \(bu 2
|
|
mode: file mode change
|
|
.IP \(bu 2
|
|
type: file type change
|
|
.IP \(bu 2
|
|
owner: file owner (user/group) change
|
|
.IP \(bu 2
|
|
group: file group change
|
|
.IP \(bu 2
|
|
user: file user change
|
|
.IP \(bu 2
|
|
link: file link change
|
|
.IP \(bu 2
|
|
directory: file directory change
|
|
.IP \(bu 2
|
|
blkdev: file block device change
|
|
.IP \(bu 2
|
|
chrdev: file character device change
|
|
.IP \(bu 2
|
|
fifo: file fifo change
|
|
.IP \(bu 2
|
|
mtime: file modification time change
|
|
.IP \(bu 2
|
|
ctime: file change time change
|
|
.IP \(bu 2
|
|
isomtime: file modification time change (ISO 8601)
|
|
.IP \(bu 2
|
|
isoctime: file creation time change (ISO 8601)
|
|
.UNINDENT
|
|
.SS What is compared
|
|
.sp
|
|
For each matching item in both archives, Borg reports:
|
|
.INDENT 0.0
|
|
.IP \(bu 2
|
|
Content changes: total added/removed bytes within files. If chunker parameters are comparable,
|
|
Borg compares chunk IDs quickly; otherwise, it compares the content. In the latter case, borg
|
|
can only tell that a file was modified, not by how much: no byte counts are given for it, the
|
|
text output shows \(dqmodified: (can\(aqt get size)\(dq instead.
|
|
.IP \(bu 2
|
|
Metadata changes: user, group, mode, and other metadata shown inline as \(dq[old \-> new]\(dq, like
|
|
\(dq[\-rw\-r\-\-r\-\- \-> \-rwxr\-xr\-x]\(dq for a mode change. Use \fB\-\-content\-only\fP to suppress metadata changes.
|
|
.IP \(bu 2
|
|
Added/removed items: printed as \(dqadded: SIZE path\(dq or \(dqremoved: SIZE path\(dq.
|
|
.UNINDENT
|
|
.SS Output formats
|
|
.sp
|
|
The default (text) output shows one line per changed path, e.g.:
|
|
.INDENT 0.0
|
|
.INDENT 3.5
|
|
.sp
|
|
.EX
|
|
modified: +23 B \-5 B [\-rwxr\-xr\-x \-> \-rw\-r\-\-r\-\-] path/to/file
|
|
added: 4 B path/to/added\-file
|
|
removed: 5 B path/to/removed\-file
|
|
.EE
|
|
.UNINDENT
|
|
.UNINDENT
|
|
.sp
|
|
JSON Lines output (\fB\-\-json\-lines\fP) prints one JSON object per changed path, with a list of
|
|
change objects. Each change object has a \(dqtype\(dq plus type\-specific data: content changes
|
|
(\(dqadded\(dq, \(dqremoved\(dq, \(dqmodified\(dq) carry \(dqadded\(dq/\(dqremoved\(dq byte counts \- except for a
|
|
\(dqmodified\(dq that was determined by comparing the content, which carries no counts at all;
|
|
metadata changes (\(dqchanged mode\(dq, \(dqchanged owner\(dq, \(dqmtime\(dq, ...) carry the old and new
|
|
values as \(dqitem1\(dq and \(dqitem2\(dq. Example:
|
|
.INDENT 0.0
|
|
.INDENT 3.5
|
|
.sp
|
|
.EX
|
|
{\(dqchanges\(dq: [{\(dqadded\(dq: 23, \(dqremoved\(dq: 5, \(dqtype\(dq: \(dqmodified\(dq}], \(dqpath\(dq: \(dqpath/to/file\(dq}
|
|
{\(dqchanges\(dq: [{\(dqtype\(dq: \(dqmodified\(dq}], \(dqpath\(dq: \(dqpath/to/other\-file\(dq}
|
|
{\(dqchanges\(dq: [{\(dqitem1\(dq: \(dq\-rw\-r\-\-r\-\-\(dq, \(dqitem2\(dq: \(dq\-rwxr\-xr\-x\(dq, \(dqtype\(dq: \(dqchanged mode\(dq}], \(dqpath\(dq: \(dqsome/file\(dq}
|
|
{\(dqchanges\(dq: [{\(dqadded\(dq: 4, \(dqremoved\(dq: 0, \(dqtype\(dq: \(dqadded\(dq}], \(dqpath\(dq: \(dqpath/to/added\-file\(dq}
|
|
{\(dqchanges\(dq: [{\(dqadded\(dq: 0, \(dqremoved\(dq: 5, \(dqtype\(dq: \(dqremoved\(dq}], \(dqpath\(dq: \(dqpath/to/removed\-file\(dq}
|
|
.EE
|
|
.UNINDENT
|
|
.UNINDENT
|
|
.SS Sorting
|
|
.sp
|
|
Use \fB\-\-sort\-by FIELDS\fP where FIELDS is a comma\-separated list of fields.
|
|
Sorts are applied stably from last to first in the given list. Prepend \(dq>\(dq for
|
|
descending, \(dq<\(dq (or no prefix) for ascending, for example \fB\-\-sort\-by=\(dq>size_added,path\(dq\fP\&.
|
|
Supported fields include:
|
|
.INDENT 0.0
|
|
.IP \(bu 2
|
|
path: the item path
|
|
.IP \(bu 2
|
|
size_added: total bytes added for the item content
|
|
.IP \(bu 2
|
|
size_removed: total bytes removed for the item content
|
|
.IP \(bu 2
|
|
size_diff: size_added \- size_removed (net content change)
|
|
.IP \(bu 2
|
|
size: size of the item as stored in ARCHIVE2 (0 for removed items)
|
|
.IP \(bu 2
|
|
user, group, uid, gid, ctime, mtime: taken from the item state in ARCHIVE2 when present
|
|
.IP \(bu 2
|
|
ctime_diff, mtime_diff: timestamp difference (ARCHIVE2 \- ARCHIVE1)
|
|
.UNINDENT
|
|
.SS Performance considerations
|
|
.sp
|
|
diff automatically detects whether the archives were created with the same chunker
|
|
parameters. If so, only chunk IDs are compared, which is very fast.
|
|
.SH SEE ALSO
|
|
.sp
|
|
\fIborg\-common(1)\fP
|
|
.SH Author
|
|
The Borg Collective
|
|
.\" End of generated man page.
|