Page tree

'subgit apply-patch' command allows one to apply patches in Git format on the top of some branch or commit. As result of the patch application a new commit is created.

It has the following mandatory options:

  • --svn-patch PATCH_FILE – specifies the patch file in Git patch format (one can use "svn diff --git --show-copies-as-adds" to generate Git patch from SVN);
  • --ref REF – target reference to create the resulting commit in: upon new commit creation this reference will be set to point to this commit.

To apply the patch in the simplest way, one can run

subgit patch --svn-patch path/to/patch.diff --ref refs/patch/result path/to/repository.git

The Git repository specified should have SubGit installated in remote mode.

To apply the patch to multiple repositories one can specify path to SubGit shared daemon path, then the patch will be applied to all repositories registered in that shared daemon.

Alternatively one can omit the Git repository path at all, in that case the patch is applied to all registered Git repositories with SubGit.

Finally, instead of specifying the path, one can specify '--revisions-file JSON_FILE' option. The JSON_FILE specified contains JSON with the following content:

"path/to/repository1.git": {"revision": "1234"},
"path/to/repository2.git": {"revision": "5678"},
"path/to/repository3.git": {"revision": "BASE"},
"path/to/repositoryN.git": {"revision": "HEAD"}

The keys are paths to Git repositories to apply patch to. The revision can be a number or one of the following values: "HEAD" and "BASE". It tells SubGit onto which revision to apply patch to.

If HEAD is specified as the revision, SubGit always fetches new changes from SVN (an analog of 'subgit fetch' command).

If BASE is specified, SubGit doesn't fetch changes from SVN but uses the latest fetched revision as the revision to apply the patch to.

If a revision number is specified, then SubGit only fetches new changes if it doesn't have that revision locally. Then it uses that revision to apply the patch to.

An alternative way to specify the revision is to use '--revision REV' option (default revision: BASE), it can be used if '--revisions-file' option is not used. Hence these 2 options are mutually exclusive.

There's a way to skip irrelevant repositories (i.e. not to apply patch to them) by using '--svn-root SVN_REPOSITORY_ROOT_URL' option. When specified, only those repositories are patched which have exactly the same SVN repository root as the option argument. This allows one to skip repositories that are definitely irrelevant to this patch.

The patch file always contains paths relative to SVN repository root (this is ensured by using "svn diff --git" command). From these paths SubGit finds out whether certain repositories are affected by the patch at all and if yes, it finds out which branches are affected. If no branch is affected, the patch application is skipped. If 2 or more branches are affected, patch application fails because only patches changing one branch are supported. For example, suppose one has an SVN repository with the following structure:

└── project
    ├── branches
    │   └── branch
    │       └── some
    │           └── file
    └── trunk
        └── some
            └── file

and suppose that SubGit is set up not for SVN repository root but for "project" directory as the project root. Then

  • if the patch changes "project/branches/branch/some/file" path, it will be applied;
  • if the patch changes "another-project/branches/branch/some/file" path, it will NOT be applied;
  • if the patch changes "project/branches/another-branch/some/file" path, it will NOT be applied;
  • if the patch changes "project/branches/branch/some/file" and "project/trunk/some/file" paths, it will fail with an error (as only one branch can be changed at a time and 'trunk' plays a role of branch, too [as well as tags]).

Using the paths in the patch file, SubGit resolves the SVN branch to apply patch to and finds its Git counterpart. With the revision specified, it finds the commit to apply patch to. Then it applies patch to that command and a new commit is created. Then SubGit sets reference specified by '–ref REF' option to this newly created commit.

There're also optional options related to the new commit creation:

  • --message or -m with argument MESSAGE allows one to specify the newly created commit message; similarly,
  • --author with argument in format like "Sherlock Holmes <>" allows one to specify the commit author;
  • --exclude-path PATTERN can be specified several times, the pattern is in svn.excludePath format and allows one to skip certain paths from patching. Note that svn.excludePath options specified in the SubGit config are respected as well, those paths are also skipped.

When running 'subgit apply-patch' not on a single repository but massively on many repositories (using shared daemon, all registered repositories, or using '--revisions-file' option) in case of failure, the command stops and doesn't continue with other repositories. But it's not impossible for a patch to change several projects located under the same SVN repository root at once. To continue with other repositories upon errors, one can use '--keep' or '-k' option.

To apply the patch, SubGit uses a temporary working directory where it checks out the current file before patch application. By default, in case of conflicts while the patch application, this directory is deleted. The '--keep-conflicts' option allows one to keep this directory to analyze the reason of the conflict and maybe to fix the patch. SubGit will print the path to this temporary directory in its output. It will also print the list of conflicted paths and the kind of the conflict (text conflict, properties conflict, or both).

The output is by default in human-readable format, but this can be changed to JSON format using '--json' option. When JSON format is chosen, SubGit prints the repository path and the newly created reference path:

"path/to/repository1.git": "refs/patch/result",
"path/to/repository2.git": "refs/patch/result",
"path/to/repository3.git": "refs/patch/result",
"path/to/repositoryN.git": "refs/patch/result"

  • No labels