PyPI: Python Package Index
SCM: Source Control Management
SOS: Subversion Offline Solution (this tool)
SVN: Apache Subversion
VCS: Version Control System
Filename: Fixed term for file names used throughout SOS and this documentation
File pattern: A filename or glob, allowing to place special characters like *?[!]
into file names to mark ellipses
File tree: A directory structure on the user's file system at a certain point. It's not exactly the same as a checkout or working copy, but largely comparable
Revision: An archived (or versioned, differential) set of file modifications, also known as changeset or patch
If you (love, or simply have to) work with the SVN VCS, but need (or lack) the flexibility of committing and branching files offline (without a permanent network connection) similar to how Git is able to, SOS is your straight-forward and super simple command-line SCM solution.
SOS allows performing offline operations a) as a drop-in replacement for svn
and other VCS, b) as an offline extension of those VCSs that either don't support offline branching and committing or are too complex, and c) as a standalone VCS.
You may run sos offline
not only inside a SVN checkout, but in any (and also multiple, even nested) folders of your file system, even outside of VCS repository checkouts/clones.
SOS thus augments SVN with offline operation and serves the same need as SVK, RCS, CVS, Git, gitless, monotone, darcs, Bazaar, Mercurial, and Fossil.
As an additional practical benefit, the sos
command will double as the command line interface of any popular VCS and will execute any svn
, git
, etc. command by sos <command> [<arguments-and-options>]
, e.g. sos commit -m "Message"
instead of svn commit -m "Message"
or git commit -m "Message"
.
Once you executed sos offline
, however, all commands are interpreted by the SOS tool instead, until leaving the offline mode via sos online
(with the exception of sos config
, cf. details below).
SOS supports three different file handling models that you may use to your liking, thus being able to mimick different traditional VCSs, plus a new mode for super quick and easy version management (the default).
commit
, update
and branch
(just like in SVN, gitless, and Fossil), requiring users to specifically add or remove files per branch. Drawback: Need to declare files to track for every offline repositorybranch
, commit
, integrate changes)pip install sos-vcs[backport]
to attempt running SOS on Python 3.3 or earlierVersion 1.7, soon to be released: Hint: The fast branching features is usable but still seen as experimental.
--remote <file system path>
arguments, or manually put a copy of your repository metadata folder (.sos
) somewhere else, set the metadata flag "remote": true
inside its .sos/.meta
and put the just created remote copy's parent folder into the remotes
list inside the .sos/.meta
file of your primary repository. To restore a remote backup, make a copy of it and set the remote
flag in .sos/.meta
to false
--no-remotes
or --exclude-remote[s]
and --include-remote[s]
with paths that match configured remote pathsdiff
, changes
, config
, status
and log
comands--exclude
for --except
and --include
for --only
--only=argument
syntax for --only argument
sos log
. Can be controlled by option flag --all
and configuration setting logLines
--verbose
and debugging output using --debug
and --log
sos log
to display number of modified text files instead of added text filessos help
display and sortingsos status
sos commit
--only
and --except
options not workingcommit
and log
useUnicodeFont
)wcwidth
library to determine visible width of unicode strings (untested)sos status
sos online
sos commit
and other operationssos offline
and sos commit
sos diff
sos diff
(not useful for sos update
, though)sos diff
is cut at the end of the (right-hand) terminal border, with the option switch --wrap
to retain the old behaviour (wrapping text around)sos status
command configurable via useChangesCommand=yes
to either show file tree status (the new default, mirroring the behaviour of SVN and Git), or display the repository and branches status (while having sos changes
for file tree status instead, especially for people coming from Fossil)typing
imports), plus removing obsolete codesos branch [<name> [<message>]] --last --fast
for instant branching that uses only a reference to the parent branch instead of copying each file. This feature goes a step into the direction of Git and introduces complexity into the code base, but was seen as essential to not stand in the way of the developer. The burden of copying revisions to dependant branches is delayed to when the parent branch is destroyed, assuming that destroying a branch is an action much less often used than branchingsos changes
and sos commit
Version 1.3, released on 2018-02-10:
sos config
sos config add
Feature 64 Added blacklisting for tracking patterns (e.g. to except single files or reduce scope of globs). For manual migration from older repositories: Add a , []
at the end of each branch info inside .sos/.meta
, e.g. modify
[0, 1518275599353, "trunk", true, []]
to
[0, 1518275599353, "trunk", true, [], []]
(note the additional trailing , []
)
sos ls
problemssos config
and added local configurations, {}
to .sos/.meta
right before the closing final ]
, and add version = "pre-1.2",
after the initial [{
log
and status
, and also ls
(in #101)destroy
--only
and --except
. Note: These have to be already tracked file patterns, currently, see #99 and #100While completing version 1.0 of SOS after almost two months of development, I incidentally discovered an interesting article by Gregory Szorc that discusses central weaknesses in the design of popular VCSs, with a focus on Git. Many of his arguments I have intuitively felt to be true as well and were the reason for the development of SOS: mainly the reduction of barriers between the developer's typical workflow and the VCS, which is most often used as a structured tool for "type and save in increments", while advanced features of Git are just very difficult to remember and get done right.
Here is a comparison between SOS and traditional VCS's commands:
branch
creates a branch from the current file tree, but also switches to it immediately. There is no requirement to name branches, removing all barriers
sos branch [<name>] --last
; this automatically applies when in tracking and picky mode.
In consequence any changes performed since last commit will automatically be considered as a change for the next commit on the branch unless --stay
was added as well, to not switch to the new branch--fast
option will store a reference to the originating branch and revision instead of copying all files. This option is currently only available when also using --last
to avoid confusion on what data is considered (not the current file tree, but the last committed revision)commit
creates a numbered revision from the current file tree, similar to how SVN does, but revision numbers are only unique per branch, as they aren't stored in a global namespace. The commit message is strictly optional on purpose (as sos commit
serves largely as a CTRL+S replacement)
sos offline
or sos branch
) always has the number 0
sos commit
increments the revision number by one; revisions are referenced by this numeric index, the revision's optional commit message if given, or a tag-1
refers to the latest revision, -2
to the second-latest/<revision>
, while specifying the latest revision of another branch by <branch>/
(note the position of the slash)delete
destroys and removes a branch. It's a command, not an option flag as in git branch -d <name>
for usability's sakeadd
and rm
add and remove tracking patterns, if the repository was created in tracking or picky mode. Patterns are never recursively applied, but always apply for a specific file tree path. They may contain, however, globs in their filename part, which makes it different from any other VCS in existencemove
renames a file tracking pattern and all matching files accordingly; only useful in tracking or picky mode. It supports reordering of literal substrings, but no reordering of glob markers (*
, ?
etc.), and of adjacent glob markers. Use --soft
to avoid files actually being renamed in the file tree. Warning: the --force
option flag will be considered for several consecutive, potentially dangerous operationsswitch
works like checkout
in Git for a revision of another branch (or of the current), or update
to latest or a specific revision in SVN. Please note that switching to a different revision will in no way fix or remember that revision. The file tree will always be compared to the branch's latest commit for change detectionupdate
works a bit like pull
and merge in Git or update
in SVN and replays the specified other (or "remote"'s) branch's and/or revision's changes into the file tree. There are plenty of options to configure what changes are actually integrated, plus interactive integration. This command will not switch the current branch like switch
does. Note, that this is not a real 3-way merge, or merge at all, just a more flexible way to insert and remove text output from diff.
When differing contents are to be merged, there is always a potential for conflict; not all changes can be merged automatically with confidence. SOS takes a simplistic and pragmatic approach and largely follows a simple diff algorithm to detect and highlight changes. Insertions and deletions are noted, and modifications are partially detected and marked as such. There are different layers of changes that SOS is able to work on:
--add
, --rm
and --ask
, which applies only for conflicts. Default is to replay both--add-lines
, --rm-lines
, --ask-lines
. Default is replay both--add-chars
, --rm-chars
, --ask-chars
. Default is to replay both--track
or --picky
mode will always combine (build the union of) all tracked file patterns. To revert this, use the switch --meta
command to pull back in another branch's and/or revision's tracking patterns to the currently active branch (may require to switch first to the other side). There is currently no check, if the pulled in tracking patterns are supersets or subsets of the onces being already thereUse the commands sos add <pattern>
or sos rm <pattern>
to add or remove file patterns. These patterns always refer to a specific (relative) file paths and may contain globbing characters ?*[!]
only in the filename part of the path.
These options can be set or unset by the user and apply either globally for all offline operations the user performs from that moment on, or locally to one repository only (using the --local
option flag).
There is currently no --system
scope (like Git supports), because SOS has been designed mainly as a single-user tool and we don't want to patronize users.
Some of these options can be defined on a per-repository basis already during offline repository creation (e.g. sos offline --track --strict --compress
), others can only be set in a persistant fashion (e.g. sos config set texttype "*.xsd"
), or after repository creation (e.g. sos config set texttype "*.xsd;*.xml" --local
).
sos config set
sets a boolean flag, a string, or an initial list (semicolon-separated)sos config unset
removes a boolean flag, a string, or an entire listsos config add
adds one or more (semicolon-separated) string entry/entries to a list, and creates it if necessarysos config rm
removes a string entry from a list. Must be typed exactly as the entry to remove. To remove the list, use sos unset <key>
sos config show
lists all defined configuration settings, including storage location/type (global, local, default)sos config show <parameter>
show only one configuration itemsos config show flags|texts|lists
show supported configurations settings per typeSOS uses the configr
library to manage per-user global defaults, e.g. for the --strict
and --track
flags that the offline
command takes, but also for often-used file and folder exclusion patterns.
By means of the sos config set <key> <value>
command, you can set these flags with values like 1
, no
, on
, false
, enable
or disabled
.
strict
: Flag for always performing full file comparsion, not only relying on modification timestamp; file size is checked always in both modes. Default: Falsetrack
: Flag for defaulting to tracking mode when going offline (SVN-style). Default: Falsepicky
: Flag for defaulting to picky mode when going offline (Git-style). Default: Falsecompress
: Flag for compressing versioned artifacts using bzip2. Default: FalseuseChangesCommand
: Flag for making sos status
into sos status --repo
and using sos changes
instead of sos status
to more closely copy Fossil's behaviouruseColorOutput
: Flag for coloring console output. Default: Depends on operating system and available librariesuseUnicodeFont
: Flag to use more fancy symbols, granted the console font supports them. Default: Depends on operating systemdefaultbranch
: Name of the initial branch created when going offline. Default: Dynamic per type of VCS in current working directory (e.g. master
for Git, trunk
for SVN, no name for Fossil)texttype
: List of file patterns that will be handled as text files, thus can be merged via textual diff, in addition to what Python's mimetypes
library will detect as a text/...
mime. Example: *.bak
could be a text file on your system, so add it to the texttype
configuration, either globally (default) or locally (using --local
). Default: Empty listbintype
: List of file patterns that should be recognized as binary files which cannot be merged textually, overriding potential matches in texttype
. Default: Empty listignores
: List of global file patterns (without any folder path) to ignore during repository operations. Any file match from the corresponding white list will negate any hit for ignores
. Default: Check utility.coco
in the source code; defaults contain e.g. ["*.bak", "*.py[cdo]]"
ignoresWhitelist
: List of file patterns to be consider even if matched by an entry in the ignores
list. Default: Empty listignoreDirs
: As ignores
, but matching folder names (not full paths)ignoreDirsWhitelist
: As ignoresWhitelist
, but for folder namessos update
will not warn if local changes are present. This is a noteworthy exception to the failsafe approach taken for most other commands--iw
or --ignore-whitespace
sos switch / --except "glob*" --except ...
or use sos switch / --only "glob*"
sos dump <targetname>.sos.zip
command, or simple move the .sos
folder into an (empty) target folder, and run sos switch trunk --force
(or use whatever branch name you're wanting to recreate).
For compressed offline repositories, you may simply tar
all files, otherwise you may want to create an compressed archive for transferring the .sos
foldersos offline --compress
: It may increase commit times by a noticeable factor (e.g. 10x), but will also reduce the amount of storage needed to version files. To enable this option for all future offline repositories, use sos config set compress on
"
), otherwise the shell might replace file patterns by the list of any matching filenames instead of forwarding the pattern literally to SOSsos st
will run sos status
, just like SVN does (but sadly not Git). Using SOS as a proxy to other VCS requires you to specify the form required by those, e.g. sos st
works for SVN, but not for Git (use sos status
instead)dirty
flag is only relevant in tracking and picky modes TODO investigate - is this true, and if yes, whysos offline
.
A workaround is to sos offline
only in the folders that are relevant for a specific task[Errno 13]
(hinting at a permission problems), don't go looking for user right problems, rather check for other processes locking files in the file tree and try again--only
or --except
for just the old or new path will lead to either only removing the old file path or only adding the new entry, prohibiting it to be recognized as a move action in the history, since the other half of the move action is missingfasteners
could even be used as a multi-user repository. Estimated development effort is 3+3 hours.python3 setup.py release
python3 setup.py clean build test
to update the PyPI version number, compile and test the code. If you need elevated rights to do so, use sudo -E python...
.git add
, git commit
and git push
and let Travis CI and AppVeyor run the tests against different target platforms. If no problems appear, continue:python3 setup.py sdist
twine upload dist/*.tar.gz
to upload the previously created distribution archive to PyPI.