The markdown parsing is broken/disabled for release notes. Sorry about that, I'm chasing the source of a crash that's been bringing this website down for the last couple of days.
### An ability to get parent hashes for log records
Extended `RepositoryLogRecord` with a new field `parentHashes` that now contains the hashes of parent commits separated by a space character. If a commit has no parents, the field will contain an empty string.
### Allow to cherry pick merge commits
Extended `GitCherryPickOptions` to allow to cherry pick merge commit. Specify the new `mainline` option (a parent number starting from 1) to cherry pick the merge commit.
### Extended sparse checkout with `set` command
Added an ability to use `set` command for `sparse-checkout`:
```swift
try repo.sparseCheckoutSet(files: ["config"])
```
### Added `--no-merges` option to `GitLogOptions`
`GitLogOptions` are now extended to contain `noMerges` option
### Sparse checkout
Sparse checkout allows to create only necessary files in the directory of the repository.
To make a sparse checkout, two steps should be performed:
- A clone operation with `--sparse` flag enabled;
- Specifying the directories that are needed to be checked out (after the clone);
`Git.framework` makes it easy to perform such operation:
```swift
let options = GitCloneOptions()
options.branches = .single(named: "main")
options.checkout = .noCheckout
options.sparse = .sparse
try repo.clone(atPath: clonePath, options: options)
guard let reference = try repo.listReferences().references.first else { return }
try repo.sparseCheckoutAdd(files: ["config"])
try repo.checkout(reference: reference)
```
In the shown example, only the directory `config` will be checked out in the working copy.
### Partial clone
Partial clone feature allows to drastically reduce the size of the downloading repository by filtering out some data during the clone operation. This can be helpful for instance during CI builds when only a part of repository is needed. Another option is to quickly clone the repo, modify a single file and then commit it to the remote.
During the clone operation the new `filter` option can be specified:
```swift
let options = GitCloneOptions()
options.filter = .omitAllBlobs
```
Or the custom filter:
```swift
let options = GitCloneOptions()
options.filter = .custom("combine:tree:3+blob:none")
```
With the combine of shallow clone (that was already implemented in the previous versions) + sparse checkout + partial clone it is possible to achieve great size optimisation during the clone operation:
```swift
let options = GitCloneOptions()
// Limit the history of the clone to a single commit
options.depth = .head
// Limit the list of branches to a single branch
options.branches = .single(named: "main")
// Do not perform a checkout
options.checkout = .noCheckout
// Indicate that the sparse checkout will be made
options.sparse = .sparse
// Omit BLOB data during the clone
options.filter = .omitAllBlobs
```
To rewrite this to the git command line:
```bash
git clone --depth=1 --no-checkout --sparse --filter=blob:none --single-branch --branch main
```
### Support for Xcode 15
This release resolves warnings introduced by Xcode 15.
In general the code still can be build by Xcode 14, but to avoid compatibility issues, the major version is increased to 3.0.0
### Support for XCFramework
XCFramework can now be created from Xcode project file. For this purpose a new scheme `Git-XCFramework` has been added to the project. The resulting `.xcframework` file can be accessed inside `XCFramework/build` directory (it is also available inside Xcode project file structure).
You may also download xcframework file attached to this release as zip archive.
### Tags support
In this release added an ability to make tags in repository with different options and list tag names.
- To create a new tag use the following command:
```swift
let repository: GitRepository
try repository.tag(options: .annotate(tag: "tag name", message: "This is a message that is used for a tag creation"))
```
- To delete a tag:
```swift
try repository.delete(tag: "tag name to delete")
```
- To create lightweight tag:
```swift
try repository.tag(options: .lightWeight(tag: "tag name")
```
- To get all possible tag names:
```swift
let tagList = try repository.listTags()
```
- Getting tags by pattern:
```swift
let tagList = try repository.listTags(options: .pattern("v-*"))
```
Thanks @jagreenwood for contribution!
> You may also find more samples in [Wiki page](https://github.com/way-to-code/git-macOS/wiki/Samples).
> **Important:**
Version is increased to 2.0.0 because API was changed slightly and migration is needed. Please read the information below.
### Public API changes
#### Changed `RepositoryReference.name` property.
In version 1.x when name property was calculated, it returned a reference name without an addional information. For example, for `refs/remotes/origin/main` it returned just `main` and for `refs/heads/main` also `main`. This behaviour was ambiguous.
From this time a name property no longer String. It has it's own type `RepositoryReferenceName` that contains a various properties for getting a reference name.
#### Renamed methods
To better correspond [Swift API Design Guidelines](https://swift.org/documentation/api-design-guidelines/) some methods were renamed:
- `GitRepository` `init(at:using:)` was renamed into `init(atPath:using:)`;
- `GitRepository` `init(from:using:)` was renamed into `init(fromUrl:using)`;
- `GitRepository` `clone(at:options:)` was renamed into `clone(atPath:options)`;
- `GitRepository` `createRepository(atPath:options:credentials:)` was renamed into `create(atPath:options:using:)`
### Added better handling for init method
`GitRepository` `init` method has been improved. Now instead of returning nil from initializer it throws an exception in case repository can not be initialized by some reason. In addition, the method now will check whether `.git` directory exists or not. When `.git` directory does not exist, an exception will be raised.
### GitReferenceList, GitRemoteList improved
Added conformance to `Sequence` for `GitReferenceList` and `GitRemoteList`. Now it is possible to interate throw the list using `for cycle`:
```swift
let remotesList = try repository.listRemotes()
for remote in remotesList {
print(remote.name)
}
```
### Migration guide to 2.0.0
#### Rename methods
1. `clone`
```swift
try repository.clone(at: localPath, options: options)
```
Becomes:
```swift
try repository.clone(atPath: localPath, options: options)
```
1. `init`
```swift
GitRepository(from: url, using: credentialsProvider)
```
Becomes:
```swift
try GitRepository(fromUrl: url, using: credentialsProvider)
```
1. `init`
```swift
GitRepository(at: path, using: credentialsProvider)
```
Becomes:
```swift
try GitRepository(atPath: path, using: credentialsProvider)
```
1. `createRepository`
```swift
GitRepository.createRepository(atPath: path)
```
Becomes:
```swift
GitRepository.create(atPath: path)
```
#### Handle RepositoryReference name changes
In case you used `RepositoryReference.name` property somehow you need to replace that code with the following:
```swift
let reference: RepositoryReference
print(reference.name)
```
Becomes:
```swift
let reference: RepositoryReference
print(reference.name.localName)
```
You may use other properties on `RepositoryReferenceName`, not just `localName`. Please refer to the documentation of `RepositoryReferenceName` within the code that covers all possible cases in details.
### Bug fixes
- Fixed a crash that could would occur when trying to get a name of `RepositoryReference` when a reference name is `refs/stash`;
- `refs/stash` and other similar names that start with `refs` and end with a name now will be correctly shown in a name of `RepositoryReference` instead of empty string.
### An ability to add remotes
Implemented a new method on `GitRepository` `addRemote(name:url:)`. This method adds a new remote to repository. This is equivalent to git command `git remote add <name> <url>`
```swift
try repository.addRemote(name: "origin", url: remoteUrl)
```
### Added -u option for push
Added a new option to `GitPushOptions`: `upstream: Bool`. When set to true this is equivalent to git `-u` or `--set-upstream` option.
### Bug fixes
Fixed a bug that caused extra quotes to be added to a branch name, when a branch is set throw the init command
### git init support
Added basic support for git init command. You may use this to create empty git repositories. An example of usage:
```swift
let repository = try GitRepository.createRepository(atPath: path)
```
There are some options are also available for this command. For instance, to set a custom initial branch name:
```swift
let options = GitInitOptions()
options.initialBranchName = "customBranch"
let repository = try GitRepository.createRepository(atPath: path, options: options)
```
Please refer to `GitInitOptions` for other available options
### git branch support
Added support for creating local branches. To create a new local branch you may use `createBranch(branchName:options:)` method on `GitRepository`. For instance:
```swift
try repository.createBranch(branchName: "yourBranchName", options: .default)
```
Please refer to `GitBranchOptions` for available options.
### Minor fixes
- Allowed initializer for `GitLogOptions` to be accessible from outside when using framework;
- Allowed `quiet` and `progress` options in `GitCloneOptions` to be accessible from outside when using framework.
### Added basic demo project
Demo project contains an example how to use Git.framework as an external package in Xcode. It also demonstrates how to use the clone feature, listing references and listing log records.