Merge branch 'master' into sh-add-ssh-retries
This commit is contained in:
commit
54d8b39d7b
@ -63,7 +63,6 @@ In general, contributors should develop on branches based off of `master` and pu
|
|||||||
0. Create a new branch based on `master`: `git checkout -b <my-branch-name> master`
|
0. Create a new branch based on `master`: `git checkout -b <my-branch-name> master`
|
||||||
0. Make your change, add tests, and make sure the tests still pass
|
0. Make your change, add tests, and make sure the tests still pass
|
||||||
0. Push to your fork and [submit a pull request][pr] from your branch to `master`
|
0. Push to your fork and [submit a pull request][pr] from your branch to `master`
|
||||||
0. Accept the [GitHub CLA][cla]
|
|
||||||
0. Pat yourself on the back and wait for your pull request to be reviewed
|
0. Pat yourself on the back and wait for your pull request to be reviewed
|
||||||
|
|
||||||
Here are a few things you can do that will increase the likelihood of your pull request being accepted:
|
Here are a few things you can do that will increase the likelihood of your pull request being accepted:
|
||||||
@ -161,4 +160,3 @@ v1.5 just shipped, set the version in master to `1.6-pre`, for example.
|
|||||||
[fork]: https://github.com/git-lfs/git-lfs/fork
|
[fork]: https://github.com/git-lfs/git-lfs/fork
|
||||||
[pr]: https://github.com/git-lfs/git-lfs/compare
|
[pr]: https://github.com/git-lfs/git-lfs/compare
|
||||||
[style]: https://github.com/golang/go/wiki/CodeReviewComments
|
[style]: https://github.com/golang/go/wiki/CodeReviewComments
|
||||||
[cla]: https://cla.github.com/git-lfs/git-lfs/accept
|
|
||||||
|
163
README.md
163
README.md
@ -11,86 +11,100 @@
|
|||||||
[5]: https://ci.appveyor.com/api/projects/status/46a5yoqc3hk59bl5/branch/master?svg=true
|
[5]: https://ci.appveyor.com/api/projects/status/46a5yoqc3hk59bl5/branch/master?svg=true
|
||||||
[6]: https://ci.appveyor.com/project/git-lfs/git-lfs/branch/master
|
[6]: https://ci.appveyor.com/project/git-lfs/git-lfs/branch/master
|
||||||
|
|
||||||
Git LFS is a command line extension and [specification](docs/spec.md) for
|
[Git LFS](https://git-lfs.github.com) is a command line extension and
|
||||||
managing large files with Git. The client is written in Go, with pre-compiled
|
[specification](docs/spec.md) for managing large files with Git.
|
||||||
binaries available for Mac, Windows, Linux, and FreeBSD. Check out the
|
|
||||||
[Git LFS website][page] for an overview of features.
|
|
||||||
|
|
||||||
[page]: https://git-lfs.github.com/
|
The client is written in Go, with pre-compiled binaries available for Mac,
|
||||||
|
Windows, Linux, and FreeBSD. Check out the [website](http://git-lfs.github.com)
|
||||||
|
for an overview of features.
|
||||||
|
|
||||||
## Getting Started
|
## Getting Started
|
||||||
|
|
||||||
By default, the Git LFS client needs a Git LFS server to sync the large files
|
### Installation
|
||||||
it manages. This works out of the box when using popular git repository
|
|
||||||
hosting providers like GitHub, Atlassian, etc. When you host your own
|
|
||||||
vanilla git server, for example, you need to either use a separate
|
|
||||||
[Git LFS server instance](https://github.com/git-lfs/git-lfs/wiki/Implementations),
|
|
||||||
or use the [custom transfer adapter](docs/custom-transfers.md) with
|
|
||||||
a transfer agent in blind mode, without having to use a Git LFS server instance.
|
|
||||||
|
|
||||||
You can install the Git LFS client in several different ways, depending on
|
You can install the Git LFS client in several different ways, depending on your
|
||||||
your setup and preferences.
|
setup and preferences.
|
||||||
|
|
||||||
* Linux users can install Debian or RPM packages from [PackageCloud](https://packagecloud.io/github/git-lfs/install). See the [Installation Guide](./INSTALLING.md) for details.
|
* **Linux users**. Debian and RPM packages are available from
|
||||||
* Mac users can install from [Homebrew](https://github.com/Homebrew/homebrew) with `brew install git-lfs`, or from [MacPorts](https://www.macports.org) with `port install git-lfs`.
|
[PackageCloud](https://packagecloud.io/github/git-lfs/install).
|
||||||
* Windows users can install from [Chocolatey](https://chocolatey.org/) with `choco install git-lfs`.
|
* **macOS users**. [Homebrew](https://brew.sh) bottles are distributed, and can
|
||||||
* [Binary packages are available][rel] for Windows, Mac, Linux, and FreeBSD.
|
be installed via `brew install git-lfs`.
|
||||||
* You can build it with Go 1.8.1+. See the [Contributing Guide](./CONTRIBUTING.md) for instructions.
|
* **Windows users**. Chocolatey packages are distributed, and can be installed
|
||||||
|
via `choco install git-lfs`.
|
||||||
|
|
||||||
[rel]: https://github.com/git-lfs/git-lfs/releases
|
In addition, [binary packages](https://github.com/git-lfs/git-lfs/releases) are
|
||||||
|
available for Linux, macOS, Windows, and FreeBSD. This repository can also be
|
||||||
|
built from source using the latest version of [Go](https://golang.org), and the
|
||||||
|
available instructions in our
|
||||||
|
[Wiki](https://github.com/git-lfs/git-lfs/wiki/Installation#source).
|
||||||
|
|
||||||
Note: Git LFS requires Git v1.8.5 or higher.
|
### Usage
|
||||||
|
|
||||||
Once installed, you need to setup the global Git hooks for Git LFS. This only
|
Git LFS requires a global installation once per-machine. This can be done by
|
||||||
needs to be done once per machine.
|
running:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
$ git lfs install
|
$ git lfs install
|
||||||
```
|
```
|
||||||
|
|
||||||
Now, it's time to add some large files to a repository. The first step is to
|
To begin using Git LFS within your Git repository, you can indicate which files
|
||||||
specify file patterns to store with Git LFS. These file patterns are stored in
|
you would like Git LFS to manage. This can be done by running the following
|
||||||
`.gitattributes`.
|
_from within Git repository_:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
$ mkdir large-repo
|
$ git lfs track "*.psd"
|
||||||
$ cd large-repo
|
|
||||||
$ git init
|
|
||||||
|
|
||||||
# Add all zip files through Git LFS
|
|
||||||
$ git lfs track "*.zip"
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Now you're ready to push some commits:
|
(Where `*.psd` is the pattern of filenames that you wish to track. You can read
|
||||||
|
more about this pattern syntax
|
||||||
|
[here](https://git-scm.com/docs/gitattributes)).
|
||||||
|
|
||||||
|
After any invocation of `git-lfs-track(1)` or `git-lfs-untrack(1)`, you _must
|
||||||
|
commit changes to your `.gitattributes` file_. This can be done by running:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
$ git add .gitattributes
|
$ git add .gitattributes
|
||||||
$ git add my.zip
|
$ git commit -m "track *.psd files using Git LFS"
|
||||||
$ git commit -m "add zip"
|
|
||||||
```
|
```
|
||||||
|
|
||||||
You can confirm that Git LFS is managing your zip file:
|
You can now interact with your Git repository as usual, and Git LFS will take
|
||||||
|
care of managing your large files. For example, changing a file named `my.psd`
|
||||||
|
(tracked above via `*.psd`):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
$ git add my.psd
|
||||||
|
$ git commit -m "add psd"
|
||||||
|
```
|
||||||
|
|
||||||
|
> _Tip:_ if you have large files already in your repository's history, `git lfs
|
||||||
|
> track` will _not_ track them retroactively. To migrate existing large files
|
||||||
|
> in your history to use Git LFS, use `git lfs migrate`. For example:
|
||||||
|
>
|
||||||
|
> ```
|
||||||
|
> $ git lfs migrate import --include="*.psd"
|
||||||
|
> ```
|
||||||
|
>
|
||||||
|
> For more information, read [`git-lfs-migrate(1)`](https://github.com/git-lfs/git-lfs/blob/master/docs/man/git-lfs-migrate.1.ronn).
|
||||||
|
|
||||||
|
You can confirm that Git LFS is managing your PSD file:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
$ git lfs ls-files
|
$ git lfs ls-files
|
||||||
my.zip
|
3c2f7aedfb * my.psd
|
||||||
```
|
```
|
||||||
|
|
||||||
Once you've made your commits, push your files to the Git remote:
|
Once you've made your commits, push your files to the Git remote:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
$ git push origin master
|
$ git push origin master
|
||||||
Sending my.zip
|
Uploading LFS objects: 100% (1/1), 810 B, 1.2 KB/s
|
||||||
LFS: 12.58 MB / 12.58 MB 100.00 %
|
# ...
|
||||||
Counting objects: 2, done.
|
|
||||||
Delta compression using up to 8 threads.
|
|
||||||
Compressing objects: 100% (5/5), done.
|
|
||||||
Writing objects: 100% (5/5), 548 bytes | 0 bytes/s, done.
|
|
||||||
Total 5 (delta 1), reused 0 (delta 0)
|
|
||||||
To https://github.com/git-lfs/git-lfs-test
|
To https://github.com/git-lfs/git-lfs-test
|
||||||
67fcf6a..47b2002 master -> master
|
67fcf6a..47b2002 master -> master
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Note: Git LFS requires Git v1.8.5 or higher.
|
||||||
|
|
||||||
## Limitations
|
## Limitations
|
||||||
|
|
||||||
Git LFS maintains a list of currently known limitations, which you can find and
|
Git LFS maintains a list of currently known limitations, which you can find and
|
||||||
@ -105,34 +119,21 @@ $ git lfs help <subcommand>
|
|||||||
```
|
```
|
||||||
|
|
||||||
The [official documentation](docs) has command references and specifications for
|
The [official documentation](docs) has command references and specifications for
|
||||||
the tool. You can ask questions in the [Git LFS chat room][chat], or [file a new
|
the tool.
|
||||||
issue][ish]. Be sure to include details about the problem so we can
|
|
||||||
troubleshoot it.
|
|
||||||
|
|
||||||
1. Include the output of `git lfs env`, which shows how your Git environment
|
You can always [open an issue](https://github.com/git-lfs/git-lfs/issues), and
|
||||||
is setup.
|
one of the Core Team members will respond to you. Please be sure to include:
|
||||||
2. Include `GIT_TRACE=1` in any bad Git commands to enable debug messages.
|
|
||||||
3. If the output includes a message like `Errors logged to /path/to/.git/lfs/objects/logs/*.log`,
|
|
||||||
throw the contents in the issue, or as a link to a Gist or paste site.
|
|
||||||
|
|
||||||
[chat]: https://gitter.im/git-lfs/git-lfs
|
1. The output of `git lfs env`, which displays helpful information about your
|
||||||
[ish]: https://github.com/git-lfs/git-lfs/issues
|
Git repository useful in debugging.
|
||||||
|
2. Any failed commands re-run with `GIT_TRACE=1` in the environment, which
|
||||||
|
displays additional information pertaining to why a command crashed.
|
||||||
|
|
||||||
## Contributing
|
## Contributing
|
||||||
|
|
||||||
See [CONTRIBUTING.md](CONTRIBUTING.md) for info on working on Git LFS and
|
See [CONTRIBUTING.md](CONTRIBUTING.md) for info on working on Git LFS and
|
||||||
sending patches. Related projects are listed on the [Implementations wiki
|
sending patches. Related projects are listed on the [Implementations wiki
|
||||||
page][impl]. You can also join [the project's chat room][chat].
|
page](https://github.com/git-lfs/git-lfs/wiki/Implementations).
|
||||||
|
|
||||||
[impl]: https://github.com/git-lfs/git-lfs/wiki/Implementations
|
|
||||||
|
|
||||||
### Using LFS from other Go code
|
|
||||||
|
|
||||||
At the moment git-lfs is only focussed on the stability of its command line
|
|
||||||
interface, and the [server APIs](docs/api/README.md). The contents of the
|
|
||||||
source packages is subject to change. We therefore currently discourage other
|
|
||||||
Go code from depending on the git-lfs packages directly; an API to be used by
|
|
||||||
external Go code may be provided in future.
|
|
||||||
|
|
||||||
## Core Team
|
## Core Team
|
||||||
|
|
||||||
@ -140,6 +141,32 @@ These are the humans that form the Git LFS core team, which runs the project.
|
|||||||
|
|
||||||
In alphabetical order:
|
In alphabetical order:
|
||||||
|
|
||||||
| [@andyneff](https://github.com/andyneff) | [@rubyist](https://github.com/rubyist) | [@sinbad](https://github.com/sinbad) | [@technoweenie](https://github.com/technoweenie) | [@ttaylorr](https://github.com/ttaylorr) |
|
| [@larsxschneider][larsxschneider-user] | [@ttaylorr][ttaylorr-user] |
|
||||||
|---|---|---|---|---|
|
|---|---|
|
||||||
| [![](https://avatars1.githubusercontent.com/u/7596961?v=3&s=100)](https://github.com/andyneff) | [![](https://avatars1.githubusercontent.com/u/143?v=3&s=100)](https://github.com/rubyist) | [![](https://avatars1.githubusercontent.com/u/142735?v=3&s=100)](https://github.com/sinbad) | [![](https://avatars3.githubusercontent.com/u/21?v=3&s=100)](https://github.com/technoweenie) | [![](https://avatars3.githubusercontent.com/u/443245?v=3&s=100)](https://github.com/ttaylorr) |
|
| [![][larsxschneider-img]][larsxschneider-user] | [![][ttaylorr-img]][ttaylorr-user] |
|
||||||
|
|
||||||
|
[larsxschneider-img]: https://avatars1.githubusercontent.com/u/477434?s=100&v=4
|
||||||
|
[ttaylorr-img]: https://avatars2.githubusercontent.com/u/443245?s=100&v=4
|
||||||
|
[larsxschneider-user]: https://github.com/larsxschneider
|
||||||
|
[ttaylorr-user]: https://github.com/ttaylorr
|
||||||
|
|
||||||
|
### Alumni
|
||||||
|
|
||||||
|
These are the humans that have in the past formed the Git LFS core team, or
|
||||||
|
have otherwise contributed a significant amount to the project. Git LFS would
|
||||||
|
not be possible without them.
|
||||||
|
|
||||||
|
In alphabetical order:
|
||||||
|
|
||||||
|
| [@andyneff][andyneff-user] | [@rubyist][rubyist-user] | [@sinbad][sinbad-user] | [@technoweenie][technoweenie-user] |
|
||||||
|
|---|---|---|---|
|
||||||
|
| [![][andyneff-img]][andyneff-user] | [![][rubyist-img]][rubyist-user] | [![][sinbad-img]][sinbad-user] | [![][technoweenie-img]][technoweenie-user] |
|
||||||
|
|
||||||
|
[andyneff-img]: https://avatars1.githubusercontent.com/u/7596961?v=3&s=100
|
||||||
|
[rubyist-img]: https://avatars1.githubusercontent.com/u/143?v=3&s=100
|
||||||
|
[sinbad-img]: https://avatars1.githubusercontent.com/u/142735?v=3&s=100
|
||||||
|
[technoweenie-img]: https://avatars3.githubusercontent.com/u/21?v=3&s=100
|
||||||
|
[andyneff-user]: https://github.com/andyneff
|
||||||
|
[sinbad-user]: https://github.com/sinbad
|
||||||
|
[rubyist-user]: https://github.com/rubyist
|
||||||
|
[technoweenie-user]: https://github.com/technoweenie
|
||||||
|
@ -3,6 +3,7 @@ package commands
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/git-lfs/git-lfs/filepathfilter"
|
"github.com/git-lfs/git-lfs/filepathfilter"
|
||||||
"github.com/git-lfs/git-lfs/git"
|
"github.com/git-lfs/git-lfs/git"
|
||||||
@ -14,6 +15,15 @@ import (
|
|||||||
|
|
||||||
func checkoutCommand(cmd *cobra.Command, args []string) {
|
func checkoutCommand(cmd *cobra.Command, args []string) {
|
||||||
requireInRepo()
|
requireInRepo()
|
||||||
|
|
||||||
|
msg := []string{
|
||||||
|
"WARNING: 'git lfs checkout' is deprecated and will be removed in v3.0.0.",
|
||||||
|
|
||||||
|
"'git checkout' has been updated in upstream Git to have comparable speeds",
|
||||||
|
"to 'git lfs checkout'.",
|
||||||
|
}
|
||||||
|
fmt.Fprintln(os.Stderr, strings.Join(msg, "\n"))
|
||||||
|
|
||||||
ref, err := git.CurrentRef()
|
ref, err := git.CurrentRef()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
Panic(err, "Could not checkout")
|
Panic(err, "Could not checkout")
|
||||||
@ -29,6 +39,7 @@ func checkoutCommand(cmd *cobra.Command, args []string) {
|
|||||||
var pointers []*lfs.WrappedPointer
|
var pointers []*lfs.WrappedPointer
|
||||||
logger := tasklog.NewLogger(os.Stdout)
|
logger := tasklog.NewLogger(os.Stdout)
|
||||||
meter := tq.NewMeter()
|
meter := tq.NewMeter()
|
||||||
|
meter.Direction = tq.Checkout
|
||||||
meter.Logger = meter.LoggerFromEnv(cfg.Os)
|
meter.Logger = meter.LoggerFromEnv(cfg.Os)
|
||||||
logger.Enqueue(meter)
|
logger.Enqueue(meter)
|
||||||
chgitscanner := lfs.NewGitScanner(func(p *lfs.WrappedPointer, err error) {
|
chgitscanner := lfs.NewGitScanner(func(p *lfs.WrappedPointer, err error) {
|
||||||
|
@ -79,6 +79,11 @@ func lockPath(file string) (string, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
wd, err = filepath.EvalSymlinks(wd)
|
||||||
|
if err != nil {
|
||||||
|
return "", errors.Wrapf(err,
|
||||||
|
"could not follow symlinks for %s", wd)
|
||||||
|
}
|
||||||
|
|
||||||
abs := filepath.Join(wd, file)
|
abs := filepath.Join(wd, file)
|
||||||
path := strings.TrimPrefix(abs, repo)
|
path := strings.TrimPrefix(abs, repo)
|
||||||
|
@ -32,6 +32,17 @@ var (
|
|||||||
|
|
||||||
// migrateVerbose enables verbose logging
|
// migrateVerbose enables verbose logging
|
||||||
migrateVerbose bool
|
migrateVerbose bool
|
||||||
|
|
||||||
|
// objectMapFile is the path to the map of old sha1 to new sha1
|
||||||
|
// commits
|
||||||
|
objectMapFilePath string
|
||||||
|
|
||||||
|
// migrateNoRewrite is the flag indicating whether or not the
|
||||||
|
// command should rewrite git history
|
||||||
|
migrateNoRewrite bool
|
||||||
|
// migrateCommitMessage is the message to use with the commit generated
|
||||||
|
// by the migrate command
|
||||||
|
migrateCommitMessage string
|
||||||
)
|
)
|
||||||
|
|
||||||
// migrate takes the given command and arguments, *odb.ObjectDatabase, as well
|
// migrate takes the given command and arguments, *odb.ObjectDatabase, as well
|
||||||
@ -85,6 +96,7 @@ func rewriteOptions(args []string, opts *githistory.RewriteOptions, l *tasklog.L
|
|||||||
|
|
||||||
UpdateRefs: opts.UpdateRefs,
|
UpdateRefs: opts.UpdateRefs,
|
||||||
Verbose: opts.Verbose,
|
Verbose: opts.Verbose,
|
||||||
|
ObjectMapFilePath: opts.ObjectMapFilePath,
|
||||||
|
|
||||||
BlobFn: opts.BlobFn,
|
BlobFn: opts.BlobFn,
|
||||||
TreeCallbackFn: opts.TreeCallbackFn,
|
TreeCallbackFn: opts.TreeCallbackFn,
|
||||||
@ -281,6 +293,9 @@ func init() {
|
|||||||
|
|
||||||
importCmd := NewCommand("import", migrateImportCommand)
|
importCmd := NewCommand("import", migrateImportCommand)
|
||||||
importCmd.Flags().BoolVar(&migrateVerbose, "verbose", false, "Verbose logging")
|
importCmd.Flags().BoolVar(&migrateVerbose, "verbose", false, "Verbose logging")
|
||||||
|
importCmd.Flags().StringVar(&objectMapFilePath, "object-map", "", "Object map file")
|
||||||
|
importCmd.Flags().BoolVar(&migrateNoRewrite, "no-rewrite", false, "Add new history without rewriting previous")
|
||||||
|
importCmd.Flags().StringVarP(&migrateCommitMessage, "message", "m", "", "With --no-rewrite, an optional commit message")
|
||||||
|
|
||||||
RegisterCommand("migrate", nil, func(cmd *cobra.Command) {
|
RegisterCommand("migrate", nil, func(cmd *cobra.Command) {
|
||||||
cmd.PersistentFlags().StringVarP(&includeArg, "include", "I", "", "Include a list of paths")
|
cmd.PersistentFlags().StringVarP(&includeArg, "include", "I", "", "Include a list of paths")
|
||||||
|
@ -9,6 +9,7 @@ import (
|
|||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/git-lfs/git-lfs/errors"
|
||||||
"github.com/git-lfs/git-lfs/filepathfilter"
|
"github.com/git-lfs/git-lfs/filepathfilter"
|
||||||
"github.com/git-lfs/git-lfs/git"
|
"github.com/git-lfs/git-lfs/git"
|
||||||
"github.com/git-lfs/git-lfs/git/githistory"
|
"github.com/git-lfs/git-lfs/git/githistory"
|
||||||
@ -29,6 +30,70 @@ func migrateImportCommand(cmd *cobra.Command, args []string) {
|
|||||||
}
|
}
|
||||||
defer db.Close()
|
defer db.Close()
|
||||||
|
|
||||||
|
if migrateNoRewrite {
|
||||||
|
if len(args) == 0 {
|
||||||
|
ExitWithError(errors.Errorf("fatal: expected one or more files with --no-rewrite"))
|
||||||
|
}
|
||||||
|
|
||||||
|
ref, err := git.CurrentRef()
|
||||||
|
if err != nil {
|
||||||
|
ExitWithError(errors.Wrap(err, "fatal: unable to find current reference"))
|
||||||
|
}
|
||||||
|
|
||||||
|
sha, _ := hex.DecodeString(ref.Sha)
|
||||||
|
commit, err := db.Commit(sha)
|
||||||
|
if err != nil {
|
||||||
|
ExitWithError(errors.Wrap(err, "fatal: unable to load commit"))
|
||||||
|
}
|
||||||
|
|
||||||
|
root := commit.TreeID
|
||||||
|
|
||||||
|
filter := git.GetAttributeFilter(cfg.LocalWorkingDir(), cfg.LocalGitDir())
|
||||||
|
if len(filter.Include()) == 0 {
|
||||||
|
ExitWithError(errors.Errorf("fatal: no Git LFS filters found in .gitattributes"))
|
||||||
|
}
|
||||||
|
|
||||||
|
gf := lfs.NewGitFilter(cfg)
|
||||||
|
|
||||||
|
for _, file := range args {
|
||||||
|
if !filter.Allows(file) {
|
||||||
|
ExitWithError(errors.Errorf("fatal: file %s did not match any Git LFS filters in .gitattributes", file))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, file := range args {
|
||||||
|
root, err = rewriteTree(gf, db, root, file)
|
||||||
|
if err != nil {
|
||||||
|
ExitWithError(errors.Wrapf(err, "fatal: could not rewrite %q", file))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
name, email := cfg.CurrentCommitter()
|
||||||
|
author := fmt.Sprintf("%s <%s>", name, email)
|
||||||
|
|
||||||
|
oid, err := db.WriteCommit(&odb.Commit{
|
||||||
|
Author: author,
|
||||||
|
Committer: author,
|
||||||
|
ParentIDs: [][]byte{sha},
|
||||||
|
Message: generateMigrateCommitMessage(cmd, strings.Join(args, ",")),
|
||||||
|
TreeID: root,
|
||||||
|
})
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
ExitWithError(errors.Wrap(err, "fatal: unable to write commit"))
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := git.UpdateRef(ref, oid, "git lfs migrate import --no-rewrite"); err != nil {
|
||||||
|
ExitWithError(errors.Wrap(err, "fatal: unable to update ref"))
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := checkoutNonBare(l); err != nil {
|
||||||
|
ExitWithError(errors.Wrap(err, "fatal: could not checkout"))
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
rewriter := getHistoryRewriter(cmd, db, l)
|
rewriter := getHistoryRewriter(cmd, db, l)
|
||||||
|
|
||||||
tracked := trackedFromFilter(rewriter.Filter())
|
tracked := trackedFromFilter(rewriter.Filter())
|
||||||
@ -37,6 +102,7 @@ func migrateImportCommand(cmd *cobra.Command, args []string) {
|
|||||||
|
|
||||||
migrate(args, rewriter, l, &githistory.RewriteOptions{
|
migrate(args, rewriter, l, &githistory.RewriteOptions{
|
||||||
Verbose: migrateVerbose,
|
Verbose: migrateVerbose,
|
||||||
|
ObjectMapFilePath: objectMapFilePath,
|
||||||
BlobFn: func(path string, b *odb.Blob) (*odb.Blob, error) {
|
BlobFn: func(path string, b *odb.Blob) (*odb.Blob, error) {
|
||||||
if filepath.Base(path) == ".gitattributes" {
|
if filepath.Base(path) == ".gitattributes" {
|
||||||
return b, nil
|
return b, nil
|
||||||
@ -70,6 +136,18 @@ func migrateImportCommand(cmd *cobra.Command, args []string) {
|
|||||||
// include set is the wildcard filepath
|
// include set is the wildcard filepath
|
||||||
// extensions of files tracked.
|
// extensions of files tracked.
|
||||||
ours = exts
|
ours = exts
|
||||||
|
|
||||||
|
if ours.Cardinality() == 0 {
|
||||||
|
// If it is still the case that we have
|
||||||
|
// no patterns to track, that means that
|
||||||
|
// we are in a tree that does not
|
||||||
|
// require .gitattributes changes.
|
||||||
|
//
|
||||||
|
// We can return early to avoid
|
||||||
|
// comparing and saving an identical
|
||||||
|
// tree.
|
||||||
|
return t, nil
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
theirs, err := trackedFromAttrs(db, t)
|
theirs, err := trackedFromAttrs(db, t)
|
||||||
@ -103,17 +181,33 @@ func migrateImportCommand(cmd *cobra.Command, args []string) {
|
|||||||
UpdateRefs: true,
|
UpdateRefs: true,
|
||||||
})
|
})
|
||||||
|
|
||||||
// Only perform `git-checkout(1) -f` if the repository is
|
if err := checkoutNonBare(l); err != nil {
|
||||||
// non-bare.
|
ExitWithError(errors.Wrap(err, "fatal: could not checkout"))
|
||||||
if bare, _ := git.IsBare(); !bare {
|
}
|
||||||
t := l.Waiter("migrate: checkout")
|
}
|
||||||
err := git.Checkout("", nil, true)
|
|
||||||
t.Complete()
|
|
||||||
|
|
||||||
if err != nil {
|
// generateMigrateCommitMessage generates a commit message used with
|
||||||
ExitWithError(err)
|
// --no-rewrite, using --message (if given) or generating one if it isn't.
|
||||||
|
func generateMigrateCommitMessage(cmd *cobra.Command, patterns string) string {
|
||||||
|
if cmd.Flag("message").Changed {
|
||||||
|
return migrateCommitMessage
|
||||||
}
|
}
|
||||||
|
return fmt.Sprintf("%s: convert to Git LFS", patterns)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// checkoutNonBare forces a checkout of the current reference, so long as the
|
||||||
|
// repository is non-bare.
|
||||||
|
//
|
||||||
|
// It returns nil on success, and a non-nil error on failure.
|
||||||
|
func checkoutNonBare(l *tasklog.Logger) error {
|
||||||
|
if bare, _ := git.IsBare(); bare {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
t := l.Waiter("migrate: checkout")
|
||||||
|
defer t.Complete()
|
||||||
|
|
||||||
|
return git.Checkout("", nil, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
// trackedFromFilter returns an ordered set of strings where each entry is a
|
// trackedFromFilter returns an ordered set of strings where each entry is a
|
||||||
@ -123,11 +217,11 @@ func trackedFromFilter(filter *filepathfilter.Filter) *tools.OrderedSet {
|
|||||||
tracked := tools.NewOrderedSet()
|
tracked := tools.NewOrderedSet()
|
||||||
|
|
||||||
for _, include := range filter.Include() {
|
for _, include := range filter.Include() {
|
||||||
tracked.Add(fmt.Sprintf("%s filter=lfs diff=lfs merge=lfs -text", include))
|
tracked.Add(fmt.Sprintf("%s filter=lfs diff=lfs merge=lfs -text", escapeAttrPattern(include)))
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, exclude := range filter.Exclude() {
|
for _, exclude := range filter.Exclude() {
|
||||||
tracked.Add(fmt.Sprintf("%s text -filter -merge -diff", exclude))
|
tracked.Add(fmt.Sprintf("%s text -filter -merge -diff", escapeAttrPattern(exclude)))
|
||||||
}
|
}
|
||||||
|
|
||||||
return tracked
|
return tracked
|
||||||
@ -201,3 +295,96 @@ func trackedToBlob(db *odb.ObjectDatabase, patterns *tools.OrderedSet) ([]byte,
|
|||||||
Size: int64(attrs.Len()),
|
Size: int64(attrs.Len()),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// rewriteTree replaces the blob at the provided path within the given tree with
|
||||||
|
// a git lfs pointer. It will recursively rewrite any subtrees along the path to the
|
||||||
|
// blob.
|
||||||
|
func rewriteTree(gf *lfs.GitFilter, db *odb.ObjectDatabase, root []byte, path string) ([]byte, error) {
|
||||||
|
tree, err := db.Tree(root)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
splits := strings.SplitN(path, "/", 2)
|
||||||
|
|
||||||
|
switch len(splits) {
|
||||||
|
case 1:
|
||||||
|
// The path points to an entry at the root of this tree, so it must be a blob.
|
||||||
|
// Try to replace this blob with a Git LFS pointer.
|
||||||
|
index := findEntry(tree, splits[0])
|
||||||
|
if index < 0 {
|
||||||
|
return nil, errors.Errorf("unable to find entry %s in tree", splits[0])
|
||||||
|
}
|
||||||
|
|
||||||
|
blobEntry := tree.Entries[index]
|
||||||
|
blob, err := db.Blob(blobEntry.Oid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var buf bytes.Buffer
|
||||||
|
|
||||||
|
if _, err := clean(gf, &buf, blob.Contents, blobEntry.Name, blob.Size); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
newOid, err := db.WriteBlob(&odb.Blob{
|
||||||
|
Contents: &buf,
|
||||||
|
Size: int64(buf.Len()),
|
||||||
|
})
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
tree = tree.Merge(&odb.TreeEntry{
|
||||||
|
Name: splits[0],
|
||||||
|
Filemode: blobEntry.Filemode,
|
||||||
|
Oid: newOid,
|
||||||
|
})
|
||||||
|
return db.WriteTree(tree)
|
||||||
|
|
||||||
|
case 2:
|
||||||
|
// The path points to an entry in a subtree contained at the root of the tree.
|
||||||
|
// Recursively rewrite the subtree.
|
||||||
|
head, tail := splits[0], splits[1]
|
||||||
|
|
||||||
|
index := findEntry(tree, head)
|
||||||
|
if index < 0 {
|
||||||
|
return nil, errors.Errorf("unable to find entry %s in tree", head)
|
||||||
|
}
|
||||||
|
|
||||||
|
subtreeEntry := tree.Entries[index]
|
||||||
|
if subtreeEntry.Type() != odb.TreeObjectType {
|
||||||
|
return nil, errors.Errorf("migrate: expected %s to be a tree, got %s", head, subtreeEntry.Type())
|
||||||
|
}
|
||||||
|
|
||||||
|
rewrittenSubtree, err := rewriteTree(gf, db, subtreeEntry.Oid, tail)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
tree = tree.Merge(&odb.TreeEntry{
|
||||||
|
Filemode: subtreeEntry.Filemode,
|
||||||
|
Name: subtreeEntry.Name,
|
||||||
|
Oid: rewrittenSubtree,
|
||||||
|
})
|
||||||
|
|
||||||
|
return db.WriteTree(tree)
|
||||||
|
|
||||||
|
default:
|
||||||
|
return nil, errors.Errorf("error parsing path %s", path)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// findEntry searches a tree for the desired entry, and returns the index of that
|
||||||
|
// entry within the tree's Entries array
|
||||||
|
func findEntry(t *odb.Tree, name string) int {
|
||||||
|
for i, entry := range t.Entries {
|
||||||
|
if entry.Name == name {
|
||||||
|
return i
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
@ -6,6 +6,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
|
"path/filepath"
|
||||||
"regexp"
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
@ -52,19 +53,29 @@ func statusCommand(cmd *cobra.Command, args []string) {
|
|||||||
ExitWithError(err)
|
ExitWithError(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
wd, _ := os.Getwd()
|
||||||
|
repo := cfg.LocalWorkingDir()
|
||||||
|
|
||||||
Print("\nGit LFS objects to be committed:\n")
|
Print("\nGit LFS objects to be committed:\n")
|
||||||
for _, entry := range staged {
|
for _, entry := range staged {
|
||||||
|
// Find a path from the current working directory to the
|
||||||
|
// absolute path of each side of the entry.
|
||||||
|
src := relativize(wd, filepath.Join(repo, entry.SrcName))
|
||||||
|
dst := relativize(wd, filepath.Join(repo, entry.DstName))
|
||||||
|
|
||||||
switch entry.Status {
|
switch entry.Status {
|
||||||
case lfs.StatusRename, lfs.StatusCopy:
|
case lfs.StatusRename, lfs.StatusCopy:
|
||||||
Print("\t%s -> %s (%s)", entry.SrcName, entry.DstName, formatBlobInfo(scanner, entry))
|
Print("\t%s -> %s (%s)", src, dst, formatBlobInfo(scanner, entry))
|
||||||
default:
|
default:
|
||||||
Print("\t%s (%s)", entry.SrcName, formatBlobInfo(scanner, entry))
|
Print("\t%s (%s)", src, formatBlobInfo(scanner, entry))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Print("\nGit LFS objects not staged for commit:\n")
|
Print("\nGit LFS objects not staged for commit:\n")
|
||||||
for _, entry := range unstaged {
|
for _, entry := range unstaged {
|
||||||
Print("\t%s (%s)", entry.SrcName, formatBlobInfo(scanner, entry))
|
src := relativize(wd, filepath.Join(repo, entry.SrcName))
|
||||||
|
|
||||||
|
Print("\t%s (%s)", src, formatBlobInfo(scanner, entry))
|
||||||
}
|
}
|
||||||
|
|
||||||
Print("")
|
Print("")
|
||||||
@ -134,7 +145,7 @@ func blobInfo(s *lfs.PointerScanner, blobSha, name string) (sha, from string, er
|
|||||||
return s.ContentsSha()[:7], from, nil
|
return s.ContentsSha()[:7], from, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
f, err := os.Open(name)
|
f, err := os.Open(filepath.Join(cfg.LocalWorkingDir(), name))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", "", err
|
return "", "", err
|
||||||
}
|
}
|
||||||
@ -311,6 +322,39 @@ func porcelainStatusLine(entry *lfs.DiffIndexEntry) string {
|
|||||||
return fmt.Sprintf("%s %s", entry.Status, entry.SrcName)
|
return fmt.Sprintf("%s %s", entry.Status, entry.SrcName)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// relativize relatives a path from "from" to "to". For instance, note that, for
|
||||||
|
// any paths "from" and "to", that:
|
||||||
|
//
|
||||||
|
// to == filepath.Clean(filepath.Join(from, relativize(from, to)))
|
||||||
|
func relativize(from, to string) string {
|
||||||
|
if len(from) == 0 {
|
||||||
|
return to
|
||||||
|
}
|
||||||
|
|
||||||
|
flist := strings.Split(filepath.ToSlash(from), "/")
|
||||||
|
tlist := strings.Split(filepath.ToSlash(to), "/")
|
||||||
|
|
||||||
|
var (
|
||||||
|
divergence int
|
||||||
|
min int
|
||||||
|
)
|
||||||
|
|
||||||
|
if lf, lt := len(flist), len(tlist); lf < lt {
|
||||||
|
min = lf
|
||||||
|
} else {
|
||||||
|
min = lt
|
||||||
|
}
|
||||||
|
|
||||||
|
for ; divergence < min; divergence++ {
|
||||||
|
if flist[divergence] != tlist[divergence] {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return strings.Repeat("../", len(flist)-divergence) +
|
||||||
|
strings.Join(tlist[divergence:], "/")
|
||||||
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
RegisterCommand("status", statusCommand, func(cmd *cobra.Command) {
|
RegisterCommand("status", statusCommand, func(cmd *cobra.Command) {
|
||||||
cmd.Flags().BoolVarP(&porcelain, "porcelain", "p", false, "Give the output in an easy-to-parse format for scripts.")
|
cmd.Flags().BoolVarP(&porcelain, "porcelain", "p", false, "Give the output in an easy-to-parse format for scripts.")
|
||||||
|
@ -49,6 +49,8 @@ func trackCommand(cmd *cobra.Command, args []string) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Intentionally do _not_ consider global- and system-level
|
||||||
|
// .gitattributes here.
|
||||||
knownPatterns := git.GetAttributePaths(cfg.LocalWorkingDir(), cfg.LocalGitDir())
|
knownPatterns := git.GetAttributePaths(cfg.LocalWorkingDir(), cfg.LocalGitDir())
|
||||||
lineEnd := getAttributeLineEnding(knownPatterns)
|
lineEnd := getAttributeLineEnding(knownPatterns)
|
||||||
if len(lineEnd) == 0 {
|
if len(lineEnd) == 0 {
|
||||||
@ -67,7 +69,7 @@ func trackCommand(cmd *cobra.Command, args []string) {
|
|||||||
var writeablePatterns []string
|
var writeablePatterns []string
|
||||||
ArgsLoop:
|
ArgsLoop:
|
||||||
for _, unsanitizedPattern := range args {
|
for _, unsanitizedPattern := range args {
|
||||||
pattern := cleanRootPath(unsanitizedPattern)
|
pattern := trimCurrentPrefix(cleanRootPath(unsanitizedPattern))
|
||||||
if !trackNoModifyAttrsFlag {
|
if !trackNoModifyAttrsFlag {
|
||||||
for _, known := range knownPatterns {
|
for _, known := range knownPatterns {
|
||||||
if known.Path == filepath.Join(relpath, pattern) &&
|
if known.Path == filepath.Join(relpath, pattern) &&
|
||||||
@ -81,7 +83,7 @@ ArgsLoop:
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Generate the new / changed attrib line for merging
|
// Generate the new / changed attrib line for merging
|
||||||
encodedArg := escapeTrackPattern(pattern)
|
encodedArg := escapeAttrPattern(pattern)
|
||||||
lockableArg := ""
|
lockableArg := ""
|
||||||
if trackLockableFlag { // no need to test trackNotLockableFlag, if we got here we're disabling
|
if trackLockableFlag { // no need to test trackNotLockableFlag, if we got here we're disabling
|
||||||
lockableArg = " " + git.LockableAttrib
|
lockableArg = " " + git.LockableAttrib
|
||||||
@ -95,7 +97,7 @@ ArgsLoop:
|
|||||||
writeablePatterns = append(writeablePatterns, pattern)
|
writeablePatterns = append(writeablePatterns, pattern)
|
||||||
}
|
}
|
||||||
|
|
||||||
Print("Tracking %q", unescapeTrackPattern(encodedArg))
|
Print("Tracking %q", unescapeAttrPattern(encodedArg))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Now read the whole local attributes file and iterate over the contents,
|
// Now read the whole local attributes file and iterate over the contents,
|
||||||
@ -213,7 +215,7 @@ ArgsLoop:
|
|||||||
}
|
}
|
||||||
|
|
||||||
func listPatterns() {
|
func listPatterns() {
|
||||||
knownPatterns := git.GetAttributePaths(cfg.LocalWorkingDir(), cfg.LocalGitDir())
|
knownPatterns := getAllKnownPatterns()
|
||||||
if len(knownPatterns) < 1 {
|
if len(knownPatterns) < 1 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -228,6 +230,14 @@ func listPatterns() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func getAllKnownPatterns() []git.AttributePath {
|
||||||
|
knownPatterns := git.GetAttributePaths(cfg.LocalWorkingDir(), cfg.LocalGitDir())
|
||||||
|
knownPatterns = append(knownPatterns, git.GetRootAttributePaths(cfg.Git)...)
|
||||||
|
knownPatterns = append(knownPatterns, git.GetSystemAttributePaths(cfg.Os)...)
|
||||||
|
|
||||||
|
return knownPatterns
|
||||||
|
}
|
||||||
|
|
||||||
func getAttributeLineEnding(attribs []git.AttributePath) string {
|
func getAttributeLineEnding(attribs []git.AttributePath) string {
|
||||||
for _, a := range attribs {
|
for _, a := range attribs {
|
||||||
if a.Source.Path == ".gitattributes" {
|
if a.Source.Path == ".gitattributes" {
|
||||||
@ -258,7 +268,7 @@ var (
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
func escapeTrackPattern(unescaped string) string {
|
func escapeAttrPattern(unescaped string) string {
|
||||||
var escaped string = strings.Replace(unescaped, `\`, "/", -1)
|
var escaped string = strings.Replace(unescaped, `\`, "/", -1)
|
||||||
|
|
||||||
for from, to := range trackEscapePatterns {
|
for from, to := range trackEscapePatterns {
|
||||||
@ -268,7 +278,7 @@ func escapeTrackPattern(unescaped string) string {
|
|||||||
return escaped
|
return escaped
|
||||||
}
|
}
|
||||||
|
|
||||||
func unescapeTrackPattern(escaped string) string {
|
func unescapeAttrPattern(escaped string) string {
|
||||||
var unescaped string = escaped
|
var unescaped string = escaped
|
||||||
|
|
||||||
for to, from := range trackEscapePatterns {
|
for to, from := range trackEscapePatterns {
|
||||||
|
@ -14,8 +14,10 @@ func uninstallCommand(cmd *cobra.Command, args []string) {
|
|||||||
uninstallHooksCommand(cmd, args)
|
uninstallHooksCommand(cmd, args)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !localInstall {
|
||||||
Print("Global Git LFS configuration has been removed.")
|
Print("Global Git LFS configuration has been removed.")
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// uninstallHooksCmd removes any hooks created by Git LFS.
|
// uninstallHooksCmd removes any hooks created by Git LFS.
|
||||||
func uninstallHooksCommand(cmd *cobra.Command, args []string) {
|
func uninstallHooksCommand(cmd *cobra.Command, args []string) {
|
||||||
|
@ -55,7 +55,7 @@ func untrackCommand(cmd *cobra.Command, args []string) {
|
|||||||
|
|
||||||
path := strings.Fields(line)[0]
|
path := strings.Fields(line)[0]
|
||||||
if removePath(path, args) {
|
if removePath(path, args) {
|
||||||
Print("Untracking %q", unescapeTrackPattern(path))
|
Print("Untracking %q", unescapeAttrPattern(path))
|
||||||
} else {
|
} else {
|
||||||
attributesFile.WriteString(line + "\n")
|
attributesFile.WriteString(line + "\n")
|
||||||
}
|
}
|
||||||
@ -63,8 +63,9 @@ func untrackCommand(cmd *cobra.Command, args []string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func removePath(path string, args []string) bool {
|
func removePath(path string, args []string) bool {
|
||||||
|
withoutCurrentDir := trimCurrentPrefix(path)
|
||||||
for _, t := range args {
|
for _, t := range args {
|
||||||
if path == escapeTrackPattern(t) {
|
if withoutCurrentDir == escapeAttrPattern(trimCurrentPrefix(t)) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -12,6 +12,24 @@ func gitLineEnding(git env) string {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
windowsPrefix = `.\`
|
||||||
|
nixPrefix = `./`
|
||||||
|
)
|
||||||
|
|
||||||
|
// trimCurrentPrefix removes a leading prefix of "./" or ".\" (referring to the
|
||||||
|
// current directory in a platform independent manner).
|
||||||
|
//
|
||||||
|
// It is useful for callers such as "git lfs track" and "git lfs untrack", that
|
||||||
|
// wish to compare filepaths and/or attributes patterns without cleaning across
|
||||||
|
// multiple platforms.
|
||||||
|
func trimCurrentPrefix(p string) string {
|
||||||
|
if strings.HasPrefix(p, windowsPrefix) {
|
||||||
|
return strings.TrimPrefix(p, windowsPrefix)
|
||||||
|
}
|
||||||
|
return strings.TrimPrefix(p, nixPrefix)
|
||||||
|
}
|
||||||
|
|
||||||
type env interface {
|
type env interface {
|
||||||
Get(string) (string, bool)
|
Get(string) (string, bool)
|
||||||
}
|
}
|
||||||
|
@ -16,6 +16,8 @@ import (
|
|||||||
var (
|
var (
|
||||||
commandFuncs []func() *cobra.Command
|
commandFuncs []func() *cobra.Command
|
||||||
commandMu sync.Mutex
|
commandMu sync.Mutex
|
||||||
|
|
||||||
|
rootVersion bool
|
||||||
)
|
)
|
||||||
|
|
||||||
// NewCommand creates a new 'git-lfs' sub command, given a command name and
|
// NewCommand creates a new 'git-lfs' sub command, given a command name and
|
||||||
@ -49,7 +51,9 @@ func RegisterCommand(name string, runFn func(cmd *cobra.Command, args []string),
|
|||||||
|
|
||||||
// Run initializes the 'git-lfs' command and runs it with the given stdin and
|
// Run initializes the 'git-lfs' command and runs it with the given stdin and
|
||||||
// command line args.
|
// command line args.
|
||||||
func Run() {
|
//
|
||||||
|
// It returns an exit code.
|
||||||
|
func Run() int {
|
||||||
log.SetOutput(ErrorWriter)
|
log.SetOutput(ErrorWriter)
|
||||||
|
|
||||||
root := NewCommand("git-lfs", gitlfsCommand)
|
root := NewCommand("git-lfs", gitlfsCommand)
|
||||||
@ -60,6 +64,8 @@ func Run() {
|
|||||||
root.SetHelpFunc(helpCommand)
|
root.SetHelpFunc(helpCommand)
|
||||||
root.SetUsageFunc(usageCommand)
|
root.SetUsageFunc(usageCommand)
|
||||||
|
|
||||||
|
root.Flags().BoolVarP(&rootVersion, "version", "v", false, "")
|
||||||
|
|
||||||
cfg = config.New()
|
cfg = config.New()
|
||||||
|
|
||||||
for _, f := range commandFuncs {
|
for _, f := range commandFuncs {
|
||||||
@ -68,14 +74,21 @@ func Run() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
root.Execute()
|
err := root.Execute()
|
||||||
closeAPIClient()
|
closeAPIClient()
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return 127
|
||||||
|
}
|
||||||
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
func gitlfsCommand(cmd *cobra.Command, args []string) {
|
func gitlfsCommand(cmd *cobra.Command, args []string) {
|
||||||
versionCommand(cmd, args)
|
versionCommand(cmd, args)
|
||||||
|
if !rootVersion {
|
||||||
cmd.Usage()
|
cmd.Usage()
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func helpCommand(cmd *cobra.Command, args []string) {
|
func helpCommand(cmd *cobra.Command, args []string) {
|
||||||
if len(args) == 0 {
|
if len(args) == 0 {
|
||||||
|
@ -4,7 +4,7 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
|
||||||
"github.com/bgentry/go-netrc/netrc"
|
"github.com/git-lfs/go-netrc/netrc"
|
||||||
)
|
)
|
||||||
|
|
||||||
type netrcfinder interface {
|
type netrcfinder interface {
|
||||||
|
1
debian/rules
vendored
1
debian/rules
vendored
@ -32,6 +32,7 @@ override_dh_clean:
|
|||||||
dh_clean
|
dh_clean
|
||||||
|
|
||||||
override_dh_auto_build:
|
override_dh_auto_build:
|
||||||
|
cd ${BUILD_DIR}/src/github.com/git-lfs/git-lfs && go generate ./commands
|
||||||
dh_auto_build
|
dh_auto_build
|
||||||
#dh_golang doesn't do anything here in deb 8, and it's needed in both
|
#dh_golang doesn't do anything here in deb 8, and it's needed in both
|
||||||
if [ "$(DEB_HOST_GNU_TYPE)" != "$(DEB_BUILD_GNU_TYPE)" ]; then\
|
if [ "$(DEB_HOST_GNU_TYPE)" != "$(DEB_BUILD_GNU_TYPE)" ]; then\
|
||||||
|
@ -7,6 +7,8 @@ git-lfs-checkout(1) -- Update working copy with file content if available
|
|||||||
|
|
||||||
## DESCRIPTION
|
## DESCRIPTION
|
||||||
|
|
||||||
|
This command is deprecated, and should be replaced with `git checkout`.
|
||||||
|
|
||||||
Try to ensure that the working copy contains file content for Git LFS objects
|
Try to ensure that the working copy contains file content for Git LFS objects
|
||||||
for the current ref, if the object data is available. Does not download any
|
for the current ref, if the object data is available. Does not download any
|
||||||
content, see git-lfs-fetch(1) for that.
|
content, see git-lfs-fetch(1) for that.
|
||||||
|
@ -80,12 +80,48 @@ options and these additional ones:
|
|||||||
* `--verbose`
|
* `--verbose`
|
||||||
Print the commit oid and filename of migrated files to STDOUT.
|
Print the commit oid and filename of migrated files to STDOUT.
|
||||||
|
|
||||||
If `--include` or `--exclude` (`-I`, `-X`, respectively) are given, the
|
* `--object-map=<path>`
|
||||||
.gitattributes will be modified to include any new filepath patterns as given by
|
Write to 'path' a file with the mapping of each rewritten commits. The file
|
||||||
those flags.
|
format is CSV with this pattern: `OLD-SHA`,`NEW-SHA`
|
||||||
|
|
||||||
If neither of those flags are given, the gitattributes will be incrementally
|
* `--no-rewrite`
|
||||||
modified to include new filepath extensions as they are rewritten in history.
|
Migrate large objects to Git LFS in a new commit without rewriting git
|
||||||
|
history. Please note that when this option is used, the `migrate import`
|
||||||
|
command will expect a different argument list, specialized options will
|
||||||
|
become available, and the core `migrate` options will be ignored. See
|
||||||
|
[IMPORT (NO REWRITE)].
|
||||||
|
|
||||||
|
If `--no-rewrite` is not provided and `--include` or `--exclude` (`-I`, `-X`,
|
||||||
|
respectively) are given, the .gitattributes will be modified to include any new
|
||||||
|
filepath patterns as given by those flags.
|
||||||
|
|
||||||
|
If `--no-rewrite` is not provided and neither of those flags are given, the
|
||||||
|
gitattributes will be incrementally modified to include new filepath extensions
|
||||||
|
as they are rewritten in history.
|
||||||
|
|
||||||
|
### IMPORT (NO REWRITE)
|
||||||
|
|
||||||
|
The `import` mode has a special sub-mode enabled by the `--no-rewrite` flag.
|
||||||
|
This sub-mode will migrate large objects to pointers as in the base `import`
|
||||||
|
mode, but will do so in a new commit without rewriting Git history. When using
|
||||||
|
this sub-mode, the base `migrate` options, such as `--include-ref`, will be
|
||||||
|
ignored, as will those for the base `import` mode. The `migrate` command will
|
||||||
|
also take a different argument list. As a result of these changes,
|
||||||
|
`--no-rewrite` will only operate on the current branch - any other interested
|
||||||
|
branches must have the generated commit merged in.
|
||||||
|
|
||||||
|
The `--no-rewrite` sub-mode supports the following options and arguments:
|
||||||
|
|
||||||
|
* `-m <message> --message=<message>`
|
||||||
|
Specifies a commit message for the newly created commit.
|
||||||
|
|
||||||
|
* [file ...]
|
||||||
|
The list of files to import. These files must be tracked by patterns
|
||||||
|
specified in the gitattributes.
|
||||||
|
|
||||||
|
If `--message` is given, the new commit will be created with the provided
|
||||||
|
message. If no message is given, a commit message will be generated based on the
|
||||||
|
file arguments.
|
||||||
|
|
||||||
## INCLUDE AND EXCLUDE
|
## INCLUDE AND EXCLUDE
|
||||||
|
|
||||||
@ -185,6 +221,20 @@ $ git lfs migrate import --everything --include="*.zip"
|
|||||||
|
|
||||||
Note: This will require a force push to any existing Git remotes.
|
Note: This will require a force push to any existing Git remotes.
|
||||||
|
|
||||||
|
### Migrate without rewriting local history
|
||||||
|
|
||||||
|
You can also migrate files without modifying the existing history of your respoitory:
|
||||||
|
|
||||||
|
Without a specified commit message:
|
||||||
|
```
|
||||||
|
git lfs migrate import --no-rewrite test.zip *.mp3 *.psd
|
||||||
|
```
|
||||||
|
With a specified commit message:
|
||||||
|
```
|
||||||
|
git lfs migrate import --no-rewrite -m "Import .zip, .mp3, .psd files" \
|
||||||
|
test.zip *.mpd *.psd
|
||||||
|
```
|
||||||
|
|
||||||
## SEE ALSO
|
## SEE ALSO
|
||||||
|
|
||||||
Part of the git-lfs(1) suite.
|
Part of the git-lfs(1) suite.
|
||||||
|
@ -59,6 +59,6 @@ to match paths.
|
|||||||
|
|
||||||
## SEE ALSO
|
## SEE ALSO
|
||||||
|
|
||||||
git-lfs-untrack(1), git-lfs-install(1), gitattributes(5).
|
git-lfs-untrack(1), git-lfs-install(1), gitattributes(5), gitignore(5).
|
||||||
|
|
||||||
Part of the git-lfs(1) suite.
|
Part of the git-lfs(1) suite.
|
||||||
|
@ -33,7 +33,7 @@ commands and low level ("plumbing") commands.
|
|||||||
Display the Git LFS environment.
|
Display the Git LFS environment.
|
||||||
* git-lfs-checkout(1):
|
* git-lfs-checkout(1):
|
||||||
Populate working copy with real content from Git LFS files.
|
Populate working copy with real content from Git LFS files.
|
||||||
* git lfs clone:
|
* git-lfs-clone(1):
|
||||||
Efficiently clone a Git LFS-enabled repository.
|
Efficiently clone a Git LFS-enabled repository.
|
||||||
* git-lfs-fetch(1):
|
* git-lfs-fetch(1):
|
||||||
Download Git LFS files from a remote.
|
Download Git LFS files from a remote.
|
||||||
@ -46,15 +46,16 @@ commands and low level ("plumbing") commands.
|
|||||||
* git-lfs-locks(1):
|
* git-lfs-locks(1):
|
||||||
List currently "locked" files from the Git LFS server.
|
List currently "locked" files from the Git LFS server.
|
||||||
* git-lfs-logs(1):
|
* git-lfs-logs(1):
|
||||||
Show errors from the git-lfs command.
|
Show errors from the Git LFS command.
|
||||||
* git-lfs-ls-files(1):
|
* git-lfs-ls-files(1):
|
||||||
Show information about Git LFS files in the index and working tree.
|
Show information about Git LFS files in the index and working tree.
|
||||||
* git-lfs-migrate(1):
|
* git-lfs-migrate(1):
|
||||||
Migrate history to or from git-lfs
|
Migrate history to or from Git LFS
|
||||||
* git-lfs-prune(1):
|
* git-lfs-prune(1):
|
||||||
Delete old Git LFS files from local storage
|
Delete old Git LFS files from local storage
|
||||||
* git-lfs-pull(1):
|
* git-lfs-pull(1):
|
||||||
Fetch LFS changes from the remote & checkout any required working tree files.
|
Fetch Git LFS changes from the remote & checkout any required working tree
|
||||||
|
files.
|
||||||
* git-lfs-push(1):
|
* git-lfs-push(1):
|
||||||
Push queued large files to the Git LFS endpoint.
|
Push queued large files to the Git LFS endpoint.
|
||||||
* git-lfs-status(1):
|
* git-lfs-status(1):
|
||||||
@ -69,7 +70,7 @@ commands and low level ("plumbing") commands.
|
|||||||
Remove Git LFS paths from Git Attributes.
|
Remove Git LFS paths from Git Attributes.
|
||||||
* git-lfs-update(1):
|
* git-lfs-update(1):
|
||||||
Update Git hooks for the current Git repository.
|
Update Git hooks for the current Git repository.
|
||||||
* git lfs version:
|
* git-lfs-version(1):
|
||||||
Report the version number.
|
Report the version number.
|
||||||
|
|
||||||
### Low level commands (plumbing)
|
### Low level commands (plumbing)
|
||||||
@ -80,5 +81,32 @@ commands and low level ("plumbing") commands.
|
|||||||
Build and compare pointers.
|
Build and compare pointers.
|
||||||
* git-lfs-pre-push(1):
|
* git-lfs-pre-push(1):
|
||||||
Git pre-push hook implementation.
|
Git pre-push hook implementation.
|
||||||
|
* git-lfs-filter-process(1):
|
||||||
|
Git process filter that converts between large files and pointers.
|
||||||
* git-lfs-smudge(1):
|
* git-lfs-smudge(1):
|
||||||
Git smudge filter that converts pointer in blobs to the actual content.
|
Git smudge filter that converts pointer in blobs to the actual content.
|
||||||
|
|
||||||
|
## EXAMPLES
|
||||||
|
|
||||||
|
To get started with Git LFS, the following commands can be used.
|
||||||
|
|
||||||
|
1. Setup Git LFS on your system. You only have to do this once per
|
||||||
|
repository per machine:
|
||||||
|
|
||||||
|
git lfs install
|
||||||
|
|
||||||
|
2. Choose the type of files you want to track, for examples all `ISO`
|
||||||
|
images, with git-lfs-track(1):
|
||||||
|
|
||||||
|
git lfs track "*.iso"
|
||||||
|
|
||||||
|
3. The above stores this information in gitattributes(5) files, so
|
||||||
|
that file need to be added to the repository:
|
||||||
|
|
||||||
|
git add .gitattributes
|
||||||
|
|
||||||
|
3. Commit, push and work with the files normally:
|
||||||
|
|
||||||
|
git add file.iso
|
||||||
|
git commit -m "Add disk image"
|
||||||
|
git push
|
||||||
|
@ -32,6 +32,7 @@ func main() {
|
|||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
commands.Run()
|
code := commands.Run()
|
||||||
once.Do(commands.Cleanup)
|
once.Do(commands.Cleanup)
|
||||||
|
os.Exit(code)
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,7 @@ import (
|
|||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/git-lfs/git-lfs/filepathfilter"
|
||||||
"github.com/git-lfs/git-lfs/tools"
|
"github.com/git-lfs/git-lfs/tools"
|
||||||
"github.com/rubyist/tracerx"
|
"github.com/rubyist/tracerx"
|
||||||
)
|
)
|
||||||
@ -34,6 +35,36 @@ func (s *AttributeSource) String() string {
|
|||||||
return s.Path
|
return s.Path
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetRootAttributePaths beahves as GetRootAttributePaths, and loads information
|
||||||
|
// only from the global gitattributes file.
|
||||||
|
func GetRootAttributePaths(cfg Env) []AttributePath {
|
||||||
|
af, ok := cfg.Get("core.attributesfile")
|
||||||
|
if !ok {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// The working directory for the root gitattributes file is blank.
|
||||||
|
return attrPaths(af, "")
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetSystemAttributePaths behaves as GetAttributePaths, and loads information
|
||||||
|
// only from the system gitattributes file, respecting the $PREFIX environment
|
||||||
|
// variable.
|
||||||
|
func GetSystemAttributePaths(env Env) []AttributePath {
|
||||||
|
prefix, _ := env.Get("PREFIX")
|
||||||
|
if len(prefix) == 0 {
|
||||||
|
prefix = string(filepath.Separator)
|
||||||
|
}
|
||||||
|
|
||||||
|
path := filepath.Join(prefix, "etc", "gitattributes")
|
||||||
|
|
||||||
|
if _, err := os.Stat(path); os.IsNotExist(err) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return attrPaths(path, "")
|
||||||
|
}
|
||||||
|
|
||||||
// GetAttributePaths returns a list of entries in .gitattributes which are
|
// GetAttributePaths returns a list of entries in .gitattributes which are
|
||||||
// configured with the filter=lfs attribute
|
// configured with the filter=lfs attribute
|
||||||
// workingDir is the root of the working copy
|
// workingDir is the root of the working copy
|
||||||
@ -42,11 +73,20 @@ func GetAttributePaths(workingDir, gitDir string) []AttributePath {
|
|||||||
paths := make([]AttributePath, 0)
|
paths := make([]AttributePath, 0)
|
||||||
|
|
||||||
for _, path := range findAttributeFiles(workingDir, gitDir) {
|
for _, path := range findAttributeFiles(workingDir, gitDir) {
|
||||||
|
paths = append(paths, attrPaths(path, workingDir)...)
|
||||||
|
}
|
||||||
|
|
||||||
|
return paths
|
||||||
|
}
|
||||||
|
|
||||||
|
func attrPaths(path, workingDir string) []AttributePath {
|
||||||
attributes, err := os.Open(path)
|
attributes, err := os.Open(path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
continue
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var paths []AttributePath
|
||||||
|
|
||||||
relfile, _ := filepath.Rel(workingDir, path)
|
relfile, _ := filepath.Rel(workingDir, path)
|
||||||
reldir := filepath.Dir(relfile)
|
reldir := filepath.Dir(relfile)
|
||||||
source := &AttributeSource{Path: relfile}
|
source := &AttributeSource{Path: relfile}
|
||||||
@ -92,11 +132,28 @@ func GetAttributePaths(workingDir, gitDir string) []AttributePath {
|
|||||||
}
|
}
|
||||||
|
|
||||||
source.LineEnding = le.LineEnding()
|
source.LineEnding = le.LineEnding()
|
||||||
}
|
|
||||||
|
|
||||||
return paths
|
return paths
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetAttributeFilter returns a list of entries in .gitattributes which are
|
||||||
|
// configured with the filter=lfs attribute as a file path filter which
|
||||||
|
// file paths can be matched against
|
||||||
|
// workingDir is the root of the working copy
|
||||||
|
// gitDir is the root of the git repo
|
||||||
|
func GetAttributeFilter(workingDir, gitDir string) *filepathfilter.Filter {
|
||||||
|
paths := GetAttributePaths(workingDir, gitDir)
|
||||||
|
patterns := make([]filepathfilter.Pattern, 0, len(paths))
|
||||||
|
|
||||||
|
for _, path := range paths {
|
||||||
|
// Convert all separators to `/` before creating a pattern to
|
||||||
|
// avoid characters being escaped in situations like `subtree\*.md`
|
||||||
|
patterns = append(patterns, filepathfilter.NewPattern(filepath.ToSlash(path.Path)))
|
||||||
|
}
|
||||||
|
|
||||||
|
return filepathfilter.NewFromPatterns(patterns, nil)
|
||||||
|
}
|
||||||
|
|
||||||
// copies bufio.ScanLines(), counting LF vs CRLF in a file
|
// copies bufio.ScanLines(), counting LF vs CRLF in a file
|
||||||
type lineEndingSplitter struct {
|
type lineEndingSplitter struct {
|
||||||
LFCount int
|
LFCount int
|
||||||
|
11
git/git.go
11
git/git.go
@ -245,7 +245,8 @@ func ResolveRef(ref string) (*Ref, error) {
|
|||||||
|
|
||||||
if len(lines) == 1 {
|
if len(lines) == 1 {
|
||||||
// ref is a sha1 and has no symbolic-full-name
|
// ref is a sha1 and has no symbolic-full-name
|
||||||
fullref.Name = lines[0] // fullref.Sha
|
fullref.Name = lines[0]
|
||||||
|
fullref.Sha = lines[0]
|
||||||
fullref.Type = RefTypeOther
|
fullref.Type = RefTypeOther
|
||||||
return fullref, nil
|
return fullref, nil
|
||||||
}
|
}
|
||||||
@ -974,7 +975,13 @@ func Fetch(remotes ...string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err := gitNoLFSSimple(append([]string{"fetch"}, remotes...)...)
|
var args []string
|
||||||
|
if len(remotes) > 1 {
|
||||||
|
args = []string{"--multiple", "--"}
|
||||||
|
}
|
||||||
|
args = append(args, remotes...)
|
||||||
|
|
||||||
|
_, err := gitNoLFSSimple(append([]string{"fetch"}, args...)...)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,6 +4,7 @@ import (
|
|||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
@ -54,6 +55,10 @@ type RewriteOptions struct {
|
|||||||
// Verbose mode prints migrated objects.
|
// Verbose mode prints migrated objects.
|
||||||
Verbose bool
|
Verbose bool
|
||||||
|
|
||||||
|
// ObjectMapFilePath is the path to the map of old sha1 to new sha1
|
||||||
|
// commits
|
||||||
|
ObjectMapFilePath string
|
||||||
|
|
||||||
// BlobFn specifies a function to rewrite blobs.
|
// BlobFn specifies a function to rewrite blobs.
|
||||||
//
|
//
|
||||||
// It is called once per unique, unchanged path. That is to say, if
|
// It is called once per unique, unchanged path. That is to say, if
|
||||||
@ -188,6 +193,15 @@ func (r *Rewriter) Rewrite(opt *RewriteOptions) ([]byte, error) {
|
|||||||
vPerc = perc
|
vPerc = perc
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var objectMapFile *os.File
|
||||||
|
if len(opt.ObjectMapFilePath) > 0 {
|
||||||
|
objectMapFile, err = os.OpenFile(opt.ObjectMapFilePath, os.O_RDWR|os.O_CREATE|os.O_EXCL, 0666)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("Could not create object map file: %v", err)
|
||||||
|
}
|
||||||
|
defer objectMapFile.Close()
|
||||||
|
}
|
||||||
|
|
||||||
// Keep track of the last commit that we rewrote. Callers often want
|
// Keep track of the last commit that we rewrote. Callers often want
|
||||||
// this so that they can perform a git-update-ref(1).
|
// this so that they can perform a git-update-ref(1).
|
||||||
var tip []byte
|
var tip []byte
|
||||||
@ -253,6 +267,11 @@ func (r *Rewriter) Rewrite(opt *RewriteOptions) ([]byte, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
if objectMapFile != nil {
|
||||||
|
if _, err := fmt.Fprintf(objectMapFile, "%x,%x\n", oid, newSha); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cache that commit so that we can reassign children of this
|
// Cache that commit so that we can reassign children of this
|
||||||
@ -322,6 +341,12 @@ func (r *Rewriter) rewriteTree(commitOID []byte, treeOID []byte, path string, fn
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If this is a symlink, skip it
|
||||||
|
if entry.Filemode == 0120000 {
|
||||||
|
entries = append(entries, copyEntry(entry))
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
if cached := r.uncacheEntry(entry); cached != nil {
|
if cached := r.uncacheEntry(entry); cached != nil {
|
||||||
entries = append(entries, copyEntry(cached))
|
entries = append(entries, copyEntry(cached))
|
||||||
continue
|
continue
|
||||||
|
@ -3,7 +3,6 @@ package githistory
|
|||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"fmt"
|
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"reflect"
|
"reflect"
|
||||||
@ -61,8 +60,8 @@ func TestRewriterRewritesHistory(t *testing.T) {
|
|||||||
//
|
//
|
||||||
// 100644 blob e440e5c842586965a7fb77deda2eca68612b1f53 hello.txt
|
// 100644 blob e440e5c842586965a7fb77deda2eca68612b1f53 hello.txt
|
||||||
|
|
||||||
AssertCommitParent(t, db, hex.EncodeToString(tip), "911994ab82ce256433c1fa739dbbbc7142156289")
|
AssertCommitParent(t, db, hex.EncodeToString(tip), "4aaa3f49ffeabbb874250fe13ffeb8c683aba650")
|
||||||
AssertCommitTree(t, db, "911994ab82ce256433c1fa739dbbbc7142156289", tree2)
|
AssertCommitTree(t, db, "4aaa3f49ffeabbb874250fe13ffeb8c683aba650", tree2)
|
||||||
|
|
||||||
AssertBlobContents(t, db, tree2, "hello.txt", "3")
|
AssertBlobContents(t, db, tree2, "hello.txt", "3")
|
||||||
|
|
||||||
@ -71,8 +70,8 @@ func TestRewriterRewritesHistory(t *testing.T) {
|
|||||||
//
|
//
|
||||||
// 100644 blob d8263ee9860594d2806b0dfd1bfd17528b0ba2a4 hello.txt
|
// 100644 blob d8263ee9860594d2806b0dfd1bfd17528b0ba2a4 hello.txt
|
||||||
|
|
||||||
AssertCommitParent(t, db, "911994ab82ce256433c1fa739dbbbc7142156289", "38679ebeba3403103196eb6272b326f96c928ace")
|
AssertCommitParent(t, db, "4aaa3f49ffeabbb874250fe13ffeb8c683aba650", "24a341e1ff75addc22e336a8d87f82ba56b86fcf")
|
||||||
AssertCommitTree(t, db, "38679ebeba3403103196eb6272b326f96c928ace", tree3)
|
AssertCommitTree(t, db, "24a341e1ff75addc22e336a8d87f82ba56b86fcf", tree3)
|
||||||
|
|
||||||
AssertBlobContents(t, db, tree3, "hello.txt", "2")
|
AssertBlobContents(t, db, tree3, "hello.txt", "2")
|
||||||
}
|
}
|
||||||
@ -112,14 +111,14 @@ func TestRewriterRewritesOctopusMerges(t *testing.T) {
|
|||||||
// parent 1fe2b9577d5610e8d8fb2c3030534036fb648393
|
// parent 1fe2b9577d5610e8d8fb2c3030534036fb648393
|
||||||
// parent ca447959bdcd20253d69b227bcc7c2e1d3126d5c
|
// parent ca447959bdcd20253d69b227bcc7c2e1d3126d5c
|
||||||
|
|
||||||
AssertCommitParent(t, db, hex.EncodeToString(tip), "89ab88fb7e11a439299aa2aa77a5d98f6629b750")
|
AssertCommitParent(t, db, hex.EncodeToString(tip), "1fe2b9577d5610e8d8fb2c3030534036fb648393")
|
||||||
AssertCommitParent(t, db, hex.EncodeToString(tip), "adf1e9085f9dd263c1bec399b995ccfa5d994721")
|
AssertCommitParent(t, db, hex.EncodeToString(tip), "ca447959bdcd20253d69b227bcc7c2e1d3126d5c")
|
||||||
|
|
||||||
// And each of those parents should contain the root commit as their own
|
// And each of those parents should contain the root commit as their own
|
||||||
// parent:
|
// parent:
|
||||||
|
|
||||||
AssertCommitParent(t, db, "89ab88fb7e11a439299aa2aa77a5d98f6629b750", "52daca68bcf750bb86289fd95f92f5b3bd202328")
|
AssertCommitParent(t, db, "1fe2b9577d5610e8d8fb2c3030534036fb648393", "9237567f379b3c83ddf53ad9a2ae3755afb62a09")
|
||||||
AssertCommitParent(t, db, "adf1e9085f9dd263c1bec399b995ccfa5d994721", "52daca68bcf750bb86289fd95f92f5b3bd202328")
|
AssertCommitParent(t, db, "ca447959bdcd20253d69b227bcc7c2e1d3126d5c", "9237567f379b3c83ddf53ad9a2ae3755afb62a09")
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestRewriterVisitsPackedObjects(t *testing.T) {
|
func TestRewriterVisitsPackedObjects(t *testing.T) {
|
||||||
@ -189,10 +188,6 @@ func TestRewriterVisitsUniqueEntriesWithIdenticalContents(t *testing.T) {
|
|||||||
|
|
||||||
tree := "bbbe0a7676523ae02234bfe874784ca2380c2d4b"
|
tree := "bbbe0a7676523ae02234bfe874784ca2380c2d4b"
|
||||||
|
|
||||||
fmt.Println(hex.EncodeToString(tip))
|
|
||||||
root, _ := db.Root()
|
|
||||||
fmt.Println(root)
|
|
||||||
|
|
||||||
AssertCommitTree(t, db, hex.EncodeToString(tip), tree)
|
AssertCommitTree(t, db, hex.EncodeToString(tip), tree)
|
||||||
|
|
||||||
// After rewriting, the HEAD state of the repository should contain a
|
// After rewriting, the HEAD state of the repository should contain a
|
||||||
@ -278,8 +273,8 @@ func TestRewriterAllowsAdditionalTreeEntries(t *testing.T) {
|
|||||||
// 100644 blob d8263ee9860594d2806b0dfd1bfd17528b0ba2a4 hello.txt
|
// 100644 blob d8263ee9860594d2806b0dfd1bfd17528b0ba2a4 hello.txt
|
||||||
// 100644 blob 0f2287157f7cb0dd40498c7a92f74b6975fa2d57 extra.txt
|
// 100644 blob 0f2287157f7cb0dd40498c7a92f74b6975fa2d57 extra.txt
|
||||||
|
|
||||||
AssertCommitParent(t, db, hex.EncodeToString(tip), "54ca0fdd5ee455d872ce4b4e379abe1c4cdc39b3")
|
AssertCommitParent(t, db, hex.EncodeToString(tip), "45af5deb9a25bc4069b15c1f5bdccb0340978707")
|
||||||
AssertCommitTree(t, db, "54ca0fdd5ee455d872ce4b4e379abe1c4cdc39b3", tree2)
|
AssertCommitTree(t, db, "45af5deb9a25bc4069b15c1f5bdccb0340978707", tree2)
|
||||||
|
|
||||||
AssertBlobContents(t, db, tree2, "hello.txt", "2")
|
AssertBlobContents(t, db, tree2, "hello.txt", "2")
|
||||||
AssertBlobContents(t, db, tree2, "extra.txt", "extra\n")
|
AssertBlobContents(t, db, tree2, "extra.txt", "extra\n")
|
||||||
@ -290,8 +285,8 @@ func TestRewriterAllowsAdditionalTreeEntries(t *testing.T) {
|
|||||||
// 100644 blob 56a6051ca2b02b04ef92d5150c9ef600403cb1de hello.txt
|
// 100644 blob 56a6051ca2b02b04ef92d5150c9ef600403cb1de hello.txt
|
||||||
// 100644 blob 0f2287157f7cb0dd40498c7a92f74b6975fa2d57 extra.txt
|
// 100644 blob 0f2287157f7cb0dd40498c7a92f74b6975fa2d57 extra.txt
|
||||||
|
|
||||||
AssertCommitParent(t, db, "54ca0fdd5ee455d872ce4b4e379abe1c4cdc39b3", "4c52196256c611d18ad718b9b68b3d54d0a6686d")
|
AssertCommitParent(t, db, "45af5deb9a25bc4069b15c1f5bdccb0340978707", "99f6bd7cd69b45494afed95b026f3e450de8304f")
|
||||||
AssertCommitTree(t, db, "4c52196256c611d18ad718b9b68b3d54d0a6686d", tree3)
|
AssertCommitTree(t, db, "99f6bd7cd69b45494afed95b026f3e450de8304f", tree3)
|
||||||
|
|
||||||
AssertBlobContents(t, db, tree3, "hello.txt", "1")
|
AssertBlobContents(t, db, tree3, "hello.txt", "1")
|
||||||
AssertBlobContents(t, db, tree3, "extra.txt", "extra\n")
|
AssertBlobContents(t, db, tree3, "extra.txt", "extra\n")
|
||||||
@ -355,8 +350,8 @@ func TestHistoryRewriterUpdatesRefs(t *testing.T) {
|
|||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
|
|
||||||
c1 := hex.EncodeToString(tip)
|
c1 := hex.EncodeToString(tip)
|
||||||
c2 := "86f7ba8f02edaca4f980cdd584ea8899e18b840c"
|
c2 := "66561fe3ae68651658e18e48053dcfe66a2e9da1"
|
||||||
c3 := "d73b8c1a294e2371b287d9b75dbed82328ad446e"
|
c3 := "8268d8486c48024a871fa42fc487dbeabd6e3d86"
|
||||||
|
|
||||||
AssertRef(t, db, "refs/heads/master", tip)
|
AssertRef(t, db, "refs/heads/master", tip)
|
||||||
|
|
||||||
@ -374,3 +369,18 @@ func TestHistoryRewriterReturnsFilter(t *testing.T) {
|
|||||||
assert.Equal(t, expected, got,
|
assert.Equal(t, expected, got,
|
||||||
"git/githistory: expected Rewriter.Filter() to return same *filepathfilter.Filter instance")
|
"git/githistory: expected Rewriter.Filter() to return same *filepathfilter.Filter instance")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// debug is meant to be called from a defer statement to aide in debugging a
|
||||||
|
// test failure among any in this file.
|
||||||
|
//
|
||||||
|
// Callers are expected to call it immediately after calling the Rewrite()
|
||||||
|
// function.
|
||||||
|
func debug(t *testing.T, db *odb.ObjectDatabase, tip []byte, err error) {
|
||||||
|
root, ok := db.Root()
|
||||||
|
|
||||||
|
t.Log(strings.Repeat("*", 80))
|
||||||
|
t.Logf("* root=%s, ok=%t\n", root, ok)
|
||||||
|
t.Logf("* tip=%x\n", tip)
|
||||||
|
t.Logf("* err=%s\n", err)
|
||||||
|
t.Log(strings.Repeat("*", 80))
|
||||||
|
}
|
||||||
|
@ -185,7 +185,11 @@ func (c *Commit) Encode(to io.Writer) (n int, err error) {
|
|||||||
n = n + n3
|
n = n + n3
|
||||||
}
|
}
|
||||||
|
|
||||||
n4, err := fmt.Fprintf(to, "\n%s", c.Message)
|
// c.Message is built from messageParts in the Decode() function.
|
||||||
|
//
|
||||||
|
// Since each entry in messageParts _does not_ contain its trailing LF,
|
||||||
|
// append an empty string to capture the final newline.
|
||||||
|
n4, err := fmt.Fprintf(to, "\n%s\n", c.Message)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return n, err
|
return n, err
|
||||||
}
|
}
|
||||||
|
@ -159,7 +159,7 @@ func TestWriteCommit(t *testing.T) {
|
|||||||
Message: "initial commit",
|
Message: "initial commit",
|
||||||
})
|
})
|
||||||
|
|
||||||
expected := "77a746376fdb591a44a4848b5ba308b2d3e2a90c"
|
expected := "fee8a35c2890cd6e0e28d24cc457fcecbd460962"
|
||||||
|
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
assert.Equal(t, expected, hex.EncodeToString(sha))
|
assert.Equal(t, expected, hex.EncodeToString(sha))
|
||||||
|
12
glide.lock
generated
12
glide.lock
generated
@ -1,18 +1,18 @@
|
|||||||
hash: bad2138ca7787101a7a23af2464319cc580f4285e90c07d11eb9f90ad3bb9604
|
hash: 5d2fbd8be4931b982d29c6ac8df833f139b28ffdb44ca062948a2386e2096a4d
|
||||||
updated: 2018-02-27T14:39:39.133796-08:00
|
updated: 2018-05-25T13:01:03.220513-07:00
|
||||||
imports:
|
imports:
|
||||||
- name: github.com/alexbrainman/sspi
|
- name: github.com/alexbrainman/sspi
|
||||||
version: 4729b3d4d8581b2db83864d1018926e4154f9406
|
version: 4729b3d4d8581b2db83864d1018926e4154f9406
|
||||||
subpackages:
|
subpackages:
|
||||||
- ntlm
|
- ntlm
|
||||||
- name: github.com/bgentry/go-netrc
|
|
||||||
version: 9fd32a8b3d3d3f9d43c341bfe098430e07609480
|
|
||||||
subpackages:
|
|
||||||
- netrc
|
|
||||||
- name: github.com/davecgh/go-spew
|
- name: github.com/davecgh/go-spew
|
||||||
version: 5215b55f46b2b919f50a1df0eaa5886afe4e3b3d
|
version: 5215b55f46b2b919f50a1df0eaa5886afe4e3b3d
|
||||||
subpackages:
|
subpackages:
|
||||||
- spew
|
- spew
|
||||||
|
- name: github.com/git-lfs/go-netrc
|
||||||
|
version: e0e9ca483a183481412e6f5a700ff20a36177503
|
||||||
|
subpackages:
|
||||||
|
- netrc
|
||||||
- name: github.com/git-lfs/wildmatch
|
- name: github.com/git-lfs/wildmatch
|
||||||
version: 8a0518641565a619e62a2738c7d4498fc345daf6
|
version: 8a0518641565a619e62a2738c7d4498fc345daf6
|
||||||
- name: github.com/inconshreveable/mousetrap
|
- name: github.com/inconshreveable/mousetrap
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
package: github.com/git-lfs/git-lfs
|
package: github.com/git-lfs/git-lfs
|
||||||
import:
|
import:
|
||||||
- package: github.com/bgentry/go-netrc
|
- package: github.com/git-lfs/go-netrc
|
||||||
version: 9fd32a8b3d3d3f9d43c341bfe098430e07609480
|
version: e0e9ca483a183481412e6f5a700ff20a36177503
|
||||||
subpackages:
|
subpackages:
|
||||||
- netrc
|
- netrc
|
||||||
- package: github.com/kr/pty
|
- package: github.com/kr/pty
|
||||||
|
@ -56,7 +56,21 @@ func filterAttribute() *Attribute {
|
|||||||
"process": "git-lfs filter-process",
|
"process": "git-lfs filter-process",
|
||||||
"required": "true",
|
"required": "true",
|
||||||
},
|
},
|
||||||
Upgradeables: upgradeables(),
|
Upgradeables: map[string][]string{
|
||||||
|
"clean": []string{
|
||||||
|
"git-lfs clean %f",
|
||||||
|
},
|
||||||
|
"smudge": []string{
|
||||||
|
"git-lfs smudge %f",
|
||||||
|
"git-lfs smudge --skip %f",
|
||||||
|
"git-lfs smudge --skip -- %f",
|
||||||
|
},
|
||||||
|
"process": []string{
|
||||||
|
"git-lfs filter",
|
||||||
|
"git-lfs filter --skip",
|
||||||
|
"git-lfs filter-process --skip",
|
||||||
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -69,24 +83,20 @@ func skipSmudgeFilterAttribute() *Attribute {
|
|||||||
"process": "git-lfs filter-process --skip",
|
"process": "git-lfs filter-process --skip",
|
||||||
"required": "true",
|
"required": "true",
|
||||||
},
|
},
|
||||||
Upgradeables: upgradeables(),
|
Upgradeables: map[string][]string{
|
||||||
}
|
"clean": []string{
|
||||||
}
|
"git-lfs clean -- %f",
|
||||||
|
},
|
||||||
func upgradeables() map[string][]string {
|
|
||||||
return map[string][]string{
|
|
||||||
"clean": []string{"git-lfs clean %f"},
|
|
||||||
"smudge": []string{
|
"smudge": []string{
|
||||||
"git-lfs smudge %f",
|
"git-lfs smudge %f",
|
||||||
"git-lfs smudge --skip %f",
|
"git-lfs smudge --skip %f",
|
||||||
"git-lfs smudge -- %f",
|
"git-lfs smudge -- %f",
|
||||||
"git-lfs smudge --skip -- %f",
|
|
||||||
},
|
},
|
||||||
"process": []string{
|
"process": []string{
|
||||||
"git-lfs filter",
|
"git-lfs filter",
|
||||||
"git-lfs filter --skip",
|
"git-lfs filter --skip",
|
||||||
"git-lfs filter-process",
|
"git-lfs filter-process",
|
||||||
"git-lfs filter-process --skip",
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,8 +9,8 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/bgentry/go-netrc/netrc"
|
|
||||||
"github.com/git-lfs/git-lfs/errors"
|
"github.com/git-lfs/git-lfs/errors"
|
||||||
|
"github.com/git-lfs/go-netrc/netrc"
|
||||||
"github.com/rubyist/tracerx"
|
"github.com/rubyist/tracerx"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -24,6 +24,10 @@ var (
|
|||||||
// authentication from netrc or git's credential helpers if necessary,
|
// authentication from netrc or git's credential helpers if necessary,
|
||||||
// supporting basic and ntlm authentication.
|
// supporting basic and ntlm authentication.
|
||||||
func (c *Client) DoWithAuth(remote string, req *http.Request) (*http.Response, error) {
|
func (c *Client) DoWithAuth(remote string, req *http.Request) (*http.Response, error) {
|
||||||
|
return c.doWithAuth(remote, req, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) doWithAuth(remote string, req *http.Request, via []*http.Request) (*http.Response, error) {
|
||||||
req.Header = c.extraHeadersFor(req)
|
req.Header = c.extraHeadersFor(req)
|
||||||
|
|
||||||
apiEndpoint, access, credHelper, credsURL, creds, err := c.getCreds(remote, req)
|
apiEndpoint, access, credHelper, credsURL, creds, err := c.getCreds(remote, req)
|
||||||
@ -31,7 +35,7 @@ func (c *Client) DoWithAuth(remote string, req *http.Request) (*http.Response, e
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
res, err := c.doWithCreds(req, credHelper, creds, credsURL, access)
|
res, err := c.doWithCreds(req, credHelper, creds, credsURL, access, via)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if errors.IsAuthError(err) {
|
if errors.IsAuthError(err) {
|
||||||
newAccess := getAuthAccess(res)
|
newAccess := getAuthAccess(res)
|
||||||
@ -45,6 +49,12 @@ func (c *Client) DoWithAuth(remote string, req *http.Request) (*http.Response, e
|
|||||||
req.Header.Del("Authorization")
|
req.Header.Del("Authorization")
|
||||||
credHelper.Reject(creds)
|
credHelper.Reject(creds)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This case represents a rejected request that
|
||||||
|
// should have been authenticated but wasn't. Do
|
||||||
|
// not count this against our redirection
|
||||||
|
// maximum, so do not recur through doWithAuth
|
||||||
|
// and instead call DoWithAuth.
|
||||||
return c.DoWithAuth(remote, req)
|
return c.DoWithAuth(remote, req)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -57,11 +67,11 @@ func (c *Client) DoWithAuth(remote string, req *http.Request) (*http.Response, e
|
|||||||
return res, err
|
return res, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Client) doWithCreds(req *http.Request, credHelper CredentialHelper, creds Creds, credsURL *url.URL, access Access) (*http.Response, error) {
|
func (c *Client) doWithCreds(req *http.Request, credHelper CredentialHelper, creds Creds, credsURL *url.URL, access Access, via []*http.Request) (*http.Response, error) {
|
||||||
if access == NTLMAccess {
|
if access == NTLMAccess {
|
||||||
return c.doWithNTLM(req, credHelper, creds, credsURL)
|
return c.doWithNTLM(req, credHelper, creds, credsURL)
|
||||||
}
|
}
|
||||||
return c.do(req)
|
return c.do(req, "", via)
|
||||||
}
|
}
|
||||||
|
|
||||||
// getCreds fills the authorization header for the given request if possible,
|
// getCreds fills the authorization header for the given request if possible,
|
||||||
@ -270,6 +280,8 @@ func hasScheme(what string) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func requestHasAuth(req *http.Request) bool {
|
func requestHasAuth(req *http.Request) bool {
|
||||||
|
// The "Authorization" string constant is safe, since we assume that all
|
||||||
|
// request headers have been canonicalized.
|
||||||
if len(req.Header.Get("Authorization")) > 0 {
|
if len(req.Header.Get("Authorization")) > 0 {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,7 @@ import (
|
|||||||
"io"
|
"io"
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"net/textproto"
|
||||||
"net/url"
|
"net/url"
|
||||||
"os"
|
"os"
|
||||||
"regexp"
|
"regexp"
|
||||||
@ -27,7 +28,18 @@ var (
|
|||||||
httpRE = regexp.MustCompile(`\Ahttps?://`)
|
httpRE = regexp.MustCompile(`\Ahttps?://`)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var hintFileUrl = strings.TrimSpace(`
|
||||||
|
hint: The remote resolves to a file:// URL, which can only work with a
|
||||||
|
hint: standalone transfer agent. See section "Using a Custom Transfer Type
|
||||||
|
hint: without the API server" in custom-transfers.md for details.
|
||||||
|
`)
|
||||||
|
|
||||||
func (c *Client) NewRequest(method string, e Endpoint, suffix string, body interface{}) (*http.Request, error) {
|
func (c *Client) NewRequest(method string, e Endpoint, suffix string, body interface{}) (*http.Request, error) {
|
||||||
|
if strings.HasPrefix(e.Url, "file://") {
|
||||||
|
// Initial `\n` to avoid overprinting `Downloading LFS...`.
|
||||||
|
fmt.Fprintf(os.Stderr, "\n%s\n", hintFileUrl)
|
||||||
|
}
|
||||||
|
|
||||||
sshRes, err := c.sshResolveWithRetries(e, method)
|
sshRes, err := c.sshResolveWithRetries(e, method)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -77,16 +89,16 @@ func joinURL(prefix, suffix string) string {
|
|||||||
func (c *Client) Do(req *http.Request) (*http.Response, error) {
|
func (c *Client) Do(req *http.Request) (*http.Response, error) {
|
||||||
req.Header = c.extraHeadersFor(req)
|
req.Header = c.extraHeadersFor(req)
|
||||||
|
|
||||||
return c.do(req)
|
return c.do(req, "", nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
// do performs an *http.Request respecting redirects, and handles the response
|
// do performs an *http.Request respecting redirects, and handles the response
|
||||||
// as defined in c.handleResponse. Notably, it does not alter the headers for
|
// as defined in c.handleResponse. Notably, it does not alter the headers for
|
||||||
// the request argument in any way.
|
// the request argument in any way.
|
||||||
func (c *Client) do(req *http.Request) (*http.Response, error) {
|
func (c *Client) do(req *http.Request, remote string, via []*http.Request) (*http.Response, error) {
|
||||||
req.Header.Set("User-Agent", UserAgent)
|
req.Header.Set("User-Agent", UserAgent)
|
||||||
|
|
||||||
res, err := c.doWithRedirects(c.httpClient(req.Host), req, nil)
|
res, err := c.doWithRedirects(c.httpClient(req.Host), req, remote, via)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return res, err
|
return res, err
|
||||||
}
|
}
|
||||||
@ -153,13 +165,20 @@ func (c *Client) extraHeaders(u *url.URL) map[string][]string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
k, v := parts[0], strings.TrimSpace(parts[1])
|
k, v := parts[0], strings.TrimSpace(parts[1])
|
||||||
|
// If header keys are given in non-canonicalized form (e.g.,
|
||||||
|
// "AUTHORIZATION" as opposed to "Authorization") they will not
|
||||||
|
// be returned in calls to net/http.Header.Get().
|
||||||
|
//
|
||||||
|
// So, we avoid this problem by first canonicalizing header keys
|
||||||
|
// for extra headers.
|
||||||
|
k = textproto.CanonicalMIMEHeaderKey(k)
|
||||||
|
|
||||||
m[k] = append(m[k], v)
|
m[k] = append(m[k], v)
|
||||||
}
|
}
|
||||||
return m
|
return m
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Client) doWithRedirects(cli *http.Client, req *http.Request, via []*http.Request) (*http.Response, error) {
|
func (c *Client) doWithRedirects(cli *http.Client, req *http.Request, remote string, via []*http.Request) (*http.Response, error) {
|
||||||
tracedReq, err := c.traceRequest(req)
|
tracedReq, err := c.traceRequest(req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -229,7 +248,14 @@ func (c *Client) doWithRedirects(cli *http.Client, req *http.Request, via []*htt
|
|||||||
return res, err
|
return res, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return c.doWithRedirects(cli, redirectedReq, via)
|
if len(req.Header.Get("Authorization")) > 0 {
|
||||||
|
// If the original request was authenticated (noted by the
|
||||||
|
// presence of the Authorization header), then recur through
|
||||||
|
// doWithAuth, retaining the requests via but only after
|
||||||
|
// authenticating the redirected request.
|
||||||
|
return c.doWithAuth(remote, redirectedReq, via)
|
||||||
|
}
|
||||||
|
return c.doWithRedirects(cli, redirectedReq, remote, via)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Client) httpClient(host string) *http.Client {
|
func (c *Client) httpClient(host string) *http.Client {
|
||||||
|
@ -1,11 +1,13 @@
|
|||||||
package lfsapi
|
package lfsapi
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/base64"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/http/httptest"
|
"net/http/httptest"
|
||||||
|
"strings"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
@ -175,6 +177,80 @@ func TestClientRedirect(t *testing.T) {
|
|||||||
assert.EqualError(t, err, "lfsapi/client: refusing insecure redirect, https->http")
|
assert.EqualError(t, err, "lfsapi/client: refusing insecure redirect, https->http")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestClientRedirectReauthenticate(t *testing.T) {
|
||||||
|
var srv1, srv2 *httptest.Server
|
||||||
|
var called1, called2 uint32
|
||||||
|
var creds1, creds2 Creds
|
||||||
|
|
||||||
|
srv1 = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
atomic.AddUint32(&called1, 1)
|
||||||
|
|
||||||
|
if hdr := r.Header.Get("Authorization"); len(hdr) > 0 {
|
||||||
|
parts := strings.SplitN(hdr, " ", 2)
|
||||||
|
typ, b64 := parts[0], parts[1]
|
||||||
|
|
||||||
|
auth, err := base64.URLEncoding.DecodeString(b64)
|
||||||
|
assert.Nil(t, err)
|
||||||
|
assert.Equal(t, "Basic", typ)
|
||||||
|
assert.Equal(t, "user1:pass1", string(auth))
|
||||||
|
|
||||||
|
http.Redirect(w, r, srv2.URL+r.URL.Path, http.StatusMovedPermanently)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
w.WriteHeader(http.StatusUnauthorized)
|
||||||
|
}))
|
||||||
|
|
||||||
|
srv2 = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
atomic.AddUint32(&called2, 1)
|
||||||
|
|
||||||
|
parts := strings.SplitN(r.Header.Get("Authorization"), " ", 2)
|
||||||
|
typ, b64 := parts[0], parts[1]
|
||||||
|
|
||||||
|
auth, err := base64.URLEncoding.DecodeString(b64)
|
||||||
|
assert.Nil(t, err)
|
||||||
|
assert.Equal(t, "Basic", typ)
|
||||||
|
assert.Equal(t, "user2:pass2", string(auth))
|
||||||
|
}))
|
||||||
|
|
||||||
|
// Change the URL of srv2 to make it appears as if it is a different
|
||||||
|
// host.
|
||||||
|
srv2.URL = strings.Replace(srv2.URL, "127.0.0.1", "0.0.0.0", 1)
|
||||||
|
|
||||||
|
creds1 = Creds(map[string]string{
|
||||||
|
"protocol": "http",
|
||||||
|
"host": strings.TrimPrefix(srv1.URL, "http://"),
|
||||||
|
|
||||||
|
"username": "user1",
|
||||||
|
"password": "pass1",
|
||||||
|
})
|
||||||
|
creds2 = Creds(map[string]string{
|
||||||
|
"protocol": "http",
|
||||||
|
"host": strings.TrimPrefix(srv2.URL, "http://"),
|
||||||
|
|
||||||
|
"username": "user2",
|
||||||
|
"password": "pass2",
|
||||||
|
})
|
||||||
|
|
||||||
|
defer srv1.Close()
|
||||||
|
defer srv2.Close()
|
||||||
|
|
||||||
|
c, err := NewClient(NewContext(nil, nil, nil))
|
||||||
|
creds := newCredentialCacher()
|
||||||
|
creds.Approve(creds1)
|
||||||
|
creds.Approve(creds2)
|
||||||
|
c.Credentials = creds
|
||||||
|
|
||||||
|
req, err := http.NewRequest("GET", srv1.URL, nil)
|
||||||
|
require.Nil(t, err)
|
||||||
|
|
||||||
|
_, err = c.DoWithAuth("", req)
|
||||||
|
assert.Nil(t, err)
|
||||||
|
|
||||||
|
// called1 is 2 since LFS tries an unauthenticated request first
|
||||||
|
assert.EqualValues(t, 2, called1)
|
||||||
|
assert.EqualValues(t, 1, called2)
|
||||||
|
}
|
||||||
|
|
||||||
func TestNewClient(t *testing.T) {
|
func TestNewClient(t *testing.T) {
|
||||||
c, err := NewClient(NewContext(nil, nil, map[string]string{
|
c, err := NewClient(NewContext(nil, nil, map[string]string{
|
||||||
"lfs.dialtimeout": "151",
|
"lfs.dialtimeout": "151",
|
||||||
|
@ -106,3 +106,10 @@ func endpointFromGitUrl(u *url.URL, e *endpointGitFinder) Endpoint {
|
|||||||
u.Scheme = e.gitProtocol
|
u.Scheme = e.gitProtocol
|
||||||
return Endpoint{Url: u.String()}
|
return Endpoint{Url: u.String()}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func endpointFromLocalPath(path string) Endpoint {
|
||||||
|
if !strings.HasSuffix(path, ".git") {
|
||||||
|
path = fmt.Sprintf("%s/.git", path)
|
||||||
|
}
|
||||||
|
return Endpoint{Url: fmt.Sprintf("file://%s", path)}
|
||||||
|
}
|
||||||
|
@ -170,6 +170,9 @@ func (e *endpointGitFinder) NewEndpointFromCloneURL(rawurl string) Endpoint {
|
|||||||
|
|
||||||
func (e *endpointGitFinder) NewEndpoint(rawurl string) Endpoint {
|
func (e *endpointGitFinder) NewEndpoint(rawurl string) Endpoint {
|
||||||
rawurl = e.ReplaceUrlAlias(rawurl)
|
rawurl = e.ReplaceUrlAlias(rawurl)
|
||||||
|
if strings.HasPrefix(rawurl, "/") {
|
||||||
|
return endpointFromLocalPath(rawurl)
|
||||||
|
}
|
||||||
u, err := url.Parse(rawurl)
|
u, err := url.Parse(rawurl)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return endpointFromBareSshUrl(rawurl)
|
return endpointFromBareSshUrl(rawurl)
|
||||||
|
@ -250,6 +250,22 @@ func TestBareGitEndpointAddsLfsSuffix(t *testing.T) {
|
|||||||
assert.Equal(t, "", e.SshPort)
|
assert.Equal(t, "", e.SshPort)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestLocalPathEndpointAddsDotGitDir(t *testing.T) {
|
||||||
|
finder := NewEndpointFinder(NewContext(nil, nil, map[string]string{
|
||||||
|
"remote.origin.url": "/local/path",
|
||||||
|
}))
|
||||||
|
e := finder.Endpoint("download", "")
|
||||||
|
assert.Equal(t, "file:///local/path/.git/info/lfs", e.Url)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestLocalPathEndpointPreservesDotGit(t *testing.T) {
|
||||||
|
finder := NewEndpointFinder(NewContext(nil, nil, map[string]string{
|
||||||
|
"remote.origin.url": "/local/path.git",
|
||||||
|
}))
|
||||||
|
e := finder.Endpoint("download", "")
|
||||||
|
assert.Equal(t, "file:///local/path.git/info/lfs", e.Url)
|
||||||
|
}
|
||||||
|
|
||||||
func TestAccessConfig(t *testing.T) {
|
func TestAccessConfig(t *testing.T) {
|
||||||
type accessTest struct {
|
type accessTest struct {
|
||||||
Access string
|
Access string
|
||||||
|
@ -4,8 +4,8 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
|
||||||
"github.com/bgentry/go-netrc/netrc"
|
|
||||||
"github.com/git-lfs/git-lfs/config"
|
"github.com/git-lfs/git-lfs/config"
|
||||||
|
"github.com/git-lfs/go-netrc/netrc"
|
||||||
)
|
)
|
||||||
|
|
||||||
type NetrcFinder interface {
|
type NetrcFinder interface {
|
||||||
|
@ -6,7 +6,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/bgentry/go-netrc/netrc"
|
"github.com/git-lfs/go-netrc/netrc"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestNetrcWithHostAndPort(t *testing.T) {
|
func TestNetrcWithHostAndPort(t *testing.T) {
|
||||||
|
@ -19,7 +19,7 @@ type ntmlCredentials struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *Client) doWithNTLM(req *http.Request, credHelper CredentialHelper, creds Creds, credsURL *url.URL) (*http.Response, error) {
|
func (c *Client) doWithNTLM(req *http.Request, credHelper CredentialHelper, creds Creds, credsURL *url.URL) (*http.Response, error) {
|
||||||
res, err := c.do(req)
|
res, err := c.do(req, "", nil)
|
||||||
if err != nil && !errors.IsAuthError(err) {
|
if err != nil && !errors.IsAuthError(err) {
|
||||||
return res, err
|
return res, err
|
||||||
}
|
}
|
||||||
@ -86,7 +86,7 @@ func (c *Client) ntlmSendMessage(req *http.Request, message []byte) (*http.Respo
|
|||||||
|
|
||||||
msg := base64.StdEncoding.EncodeToString(message)
|
msg := base64.StdEncoding.EncodeToString(message)
|
||||||
req.Header.Set("Authorization", "NTLM "+msg)
|
req.Header.Set("Authorization", "NTLM "+msg)
|
||||||
return c.do(req)
|
return c.do(req, "", nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseChallengeResponse(res *http.Response) ([]byte, error) {
|
func parseChallengeResponse(res *http.Response) ([]byte, error) {
|
||||||
|
@ -49,13 +49,6 @@ func proxyFromClient(c *Client) func(req *http.Request) (*url.URL, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func getProxyServers(u *url.URL, urlCfg *config.URLConfig, osEnv config.Environment) (httpsProxy string, httpProxy string, noProxy string) {
|
func getProxyServers(u *url.URL, urlCfg *config.URLConfig, osEnv config.Environment) (httpsProxy string, httpProxy string, noProxy string) {
|
||||||
if urlCfg != nil {
|
|
||||||
httpProxy, _ = urlCfg.Get("http", u.String(), "proxy")
|
|
||||||
if strings.HasPrefix(httpProxy, "https://") {
|
|
||||||
httpsProxy = httpProxy
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if osEnv == nil {
|
if osEnv == nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -76,6 +69,16 @@ func getProxyServers(u *url.URL, urlCfg *config.URLConfig, osEnv config.Environm
|
|||||||
httpProxy, _ = osEnv.Get("http_proxy")
|
httpProxy, _ = osEnv.Get("http_proxy")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if urlCfg != nil {
|
||||||
|
gitProxy, ok := urlCfg.Get("http", u.String(), "proxy")
|
||||||
|
if len(gitProxy) > 0 && ok {
|
||||||
|
if strings.HasPrefix(gitProxy, "https://") {
|
||||||
|
httpsProxy = gitProxy
|
||||||
|
}
|
||||||
|
httpProxy = gitProxy
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
noProxy, _ = osEnv.Get("NO_PROXY")
|
noProxy, _ = osEnv.Get("NO_PROXY")
|
||||||
if len(noProxy) == 0 {
|
if len(noProxy) == 0 {
|
||||||
noProxy, _ = osEnv.Get("no_proxy")
|
noProxy, _ = osEnv.Get("no_proxy")
|
||||||
|
@ -20,7 +20,7 @@ func TestHttpsProxyFromGitConfig(t *testing.T) {
|
|||||||
require.Nil(t, err)
|
require.Nil(t, err)
|
||||||
|
|
||||||
proxyURL, err := proxyFromClient(c)(req)
|
proxyURL, err := proxyFromClient(c)(req)
|
||||||
assert.Equal(t, "proxy-from-git-config:8080", proxyURL.Host)
|
assert.Equal(t, "proxy-from-env:8080", proxyURL.Host)
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -62,6 +62,7 @@ $distro_name_map = {
|
|||||||
ubuntu/yakkety
|
ubuntu/yakkety
|
||||||
ubuntu/zesty
|
ubuntu/zesty
|
||||||
ubuntu/artful
|
ubuntu/artful
|
||||||
|
ubuntu/bionic
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -41,12 +41,13 @@ begin_test "checkout"
|
|||||||
rm -rf file1.dat file2.dat file3.dat folder1/nested.dat folder2/nested.dat
|
rm -rf file1.dat file2.dat file3.dat folder1/nested.dat folder2/nested.dat
|
||||||
|
|
||||||
echo "checkout should replace all"
|
echo "checkout should replace all"
|
||||||
git lfs checkout
|
git lfs checkout 2>&1 | tee checkout.log
|
||||||
[ "$contents" = "$(cat file1.dat)" ]
|
[ "$contents" = "$(cat file1.dat)" ]
|
||||||
[ "$contents" = "$(cat file2.dat)" ]
|
[ "$contents" = "$(cat file2.dat)" ]
|
||||||
[ "$contents" = "$(cat file3.dat)" ]
|
[ "$contents" = "$(cat file3.dat)" ]
|
||||||
[ "$contents" = "$(cat folder1/nested.dat)" ]
|
[ "$contents" = "$(cat folder1/nested.dat)" ]
|
||||||
[ "$contents" = "$(cat folder2/nested.dat)" ]
|
[ "$contents" = "$(cat folder2/nested.dat)" ]
|
||||||
|
grep "Checking out LFS objects: 100% (5/5), 95 B" checkout.log
|
||||||
|
|
||||||
# Remove the working directory
|
# Remove the working directory
|
||||||
rm -rf file1.dat file2.dat file3.dat folder1/nested.dat folder2/nested.dat
|
rm -rf file1.dat file2.dat file3.dat folder1/nested.dat folder2/nested.dat
|
||||||
@ -73,7 +74,7 @@ begin_test "checkout"
|
|||||||
[ ! -f ../folder2/nested.dat ]
|
[ ! -f ../folder2/nested.dat ]
|
||||||
# test '.' in current dir
|
# test '.' in current dir
|
||||||
rm nested.dat
|
rm nested.dat
|
||||||
git lfs checkout .
|
git lfs checkout . 2>&1 | tee checkout.log
|
||||||
[ "$contents" = "$(cat nested.dat)" ]
|
[ "$contents" = "$(cat nested.dat)" ]
|
||||||
popd
|
popd
|
||||||
|
|
||||||
|
@ -259,6 +259,39 @@ begin_test "credentials from netrc"
|
|||||||
)
|
)
|
||||||
end_test
|
end_test
|
||||||
|
|
||||||
|
begin_test "credentials from netrc with unknown keyword"
|
||||||
|
(
|
||||||
|
set -e
|
||||||
|
|
||||||
|
printf "machine localhost\nlogin netrcuser\nnot-a-key something\npassword netrcpass\n" >> "$NETRCFILE"
|
||||||
|
echo $HOME
|
||||||
|
echo "GITSERVER $GITSERVER"
|
||||||
|
cat $NETRCFILE
|
||||||
|
|
||||||
|
# prevent prompts on Windows particularly
|
||||||
|
export SSH_ASKPASS=
|
||||||
|
|
||||||
|
reponame="netrctest"
|
||||||
|
setup_remote_repo "$reponame"
|
||||||
|
|
||||||
|
clone_repo "$reponame" repo2
|
||||||
|
|
||||||
|
# Need a remote named "localhost" or 127.0.0.1 in netrc will interfere with the other auth
|
||||||
|
git remote add "netrc" "$(echo $GITSERVER | sed s/127.0.0.1/localhost/)/netrctest"
|
||||||
|
git lfs env
|
||||||
|
|
||||||
|
git lfs track "*.dat"
|
||||||
|
echo "push a" > a.dat
|
||||||
|
git add .gitattributes a.dat
|
||||||
|
git commit -m "add a.dat"
|
||||||
|
|
||||||
|
GIT_TRACE=1 git lfs push netrc master 2>&1 | tee push.log
|
||||||
|
grep "Uploading LFS objects: 100% (1/1), 7 B" push.log
|
||||||
|
echo "any git credential calls:"
|
||||||
|
[ "0" -eq "$(cat push.log | grep "git credential" | wc -l)" ]
|
||||||
|
)
|
||||||
|
end_test
|
||||||
|
|
||||||
begin_test "credentials from netrc with bad password"
|
begin_test "credentials from netrc with bad password"
|
||||||
(
|
(
|
||||||
set -e
|
set -e
|
||||||
@ -274,7 +307,7 @@ begin_test "credentials from netrc with bad password"
|
|||||||
reponame="netrctest"
|
reponame="netrctest"
|
||||||
setup_remote_repo "$reponame"
|
setup_remote_repo "$reponame"
|
||||||
|
|
||||||
clone_repo "$reponame" repo2
|
clone_repo "$reponame" repo3
|
||||||
|
|
||||||
# Need a remote named "localhost" or 127.0.0.1 in netrc will interfere with the other auth
|
# Need a remote named "localhost" or 127.0.0.1 in netrc will interfere with the other auth
|
||||||
git remote add "netrc" "$(echo $GITSERVER | sed s/127.0.0.1/localhost/)/netrctest"
|
git remote add "netrc" "$(echo $GITSERVER | sed s/127.0.0.1/localhost/)/netrctest"
|
||||||
|
@ -50,7 +50,7 @@ UploadTransfers=basic
|
|||||||
%s
|
%s
|
||||||
%s
|
%s
|
||||||
' "$(git lfs version)" "$(git version)" "$localwd" "$localgit" "$localgitstore" "$localmedia" "$tempdir" "$lfsstorage" "$envVars" "$envInitConfig")
|
' "$(git lfs version)" "$(git version)" "$localwd" "$localgit" "$localgitstore" "$localmedia" "$tempdir" "$lfsstorage" "$envVars" "$envInitConfig")
|
||||||
actual=$(git lfs env)
|
actual=$(git lfs env | grep -v "^GIT_EXEC_PATH=")
|
||||||
|
|
||||||
contains_same_elements "$expected" "$actual"
|
contains_same_elements "$expected" "$actual"
|
||||||
)
|
)
|
||||||
@ -102,12 +102,12 @@ UploadTransfers=basic
|
|||||||
%s
|
%s
|
||||||
%s
|
%s
|
||||||
' "$(git lfs version)" "$(git version)" "$endpoint" "$localwd" "$localgit" "$localgitstore" "$localmedia" "$tempdir" "$lfsstorage" "$envVars" "$envInitConfig")
|
' "$(git lfs version)" "$(git version)" "$endpoint" "$localwd" "$localgit" "$localgitstore" "$localmedia" "$tempdir" "$lfsstorage" "$envVars" "$envInitConfig")
|
||||||
actual=$(git lfs env)
|
actual=$(git lfs env | grep -v "^GIT_EXEC_PATH=")
|
||||||
contains_same_elements "$expected" "$actual"
|
contains_same_elements "$expected" "$actual"
|
||||||
|
|
||||||
cd .git
|
cd .git
|
||||||
expected2=$(echo "$expected" | sed -e 's/LocalWorkingDir=.*/LocalWorkingDir=/')
|
expected2=$(echo "$expected" | sed -e 's/LocalWorkingDir=.*/LocalWorkingDir=/')
|
||||||
actual2=$(git lfs env)
|
actual2=$(git lfs env | grep -v "^GIT_EXEC_PATH=")
|
||||||
contains_same_elements "$expected2" "$actual2"
|
contains_same_elements "$expected2" "$actual2"
|
||||||
)
|
)
|
||||||
end_test
|
end_test
|
||||||
@ -161,12 +161,12 @@ UploadTransfers=basic
|
|||||||
%s
|
%s
|
||||||
%s
|
%s
|
||||||
' "$(git lfs version)" "$(git version)" "$endpoint" "$endpoint2" "$localwd" "$localgit" "$localgitstore" "$localmedia" "$tempdir" "$lfsstorage" "$envVars" "$envInitConfig")
|
' "$(git lfs version)" "$(git version)" "$endpoint" "$endpoint2" "$localwd" "$localgit" "$localgitstore" "$localmedia" "$tempdir" "$lfsstorage" "$envVars" "$envInitConfig")
|
||||||
actual=$(git lfs env)
|
actual=$(git lfs env | grep -v "^GIT_EXEC_PATH=")
|
||||||
contains_same_elements "$expected" "$actual"
|
contains_same_elements "$expected" "$actual"
|
||||||
|
|
||||||
cd .git
|
cd .git
|
||||||
expected2=$(echo "$expected" | sed -e 's/LocalWorkingDir=.*/LocalWorkingDir=/')
|
expected2=$(echo "$expected" | sed -e 's/LocalWorkingDir=.*/LocalWorkingDir=/')
|
||||||
actual2=$(git lfs env)
|
actual2=$(git lfs env | grep -v "^GIT_EXEC_PATH=")
|
||||||
contains_same_elements "$expected2" "$actual2"
|
contains_same_elements "$expected2" "$actual2"
|
||||||
)
|
)
|
||||||
end_test
|
end_test
|
||||||
@ -218,12 +218,12 @@ UploadTransfers=basic
|
|||||||
%s
|
%s
|
||||||
%s
|
%s
|
||||||
' "$(git lfs version)" "$(git version)" "$endpoint" "$localwd" "$localgit" "$localgitstore" "$localmedia" "$tempdir" "$lfsstorage" "$envVars" "$envInitConfig")
|
' "$(git lfs version)" "$(git version)" "$endpoint" "$localwd" "$localgit" "$localgitstore" "$localmedia" "$tempdir" "$lfsstorage" "$envVars" "$envInitConfig")
|
||||||
actual=$(git lfs env)
|
actual=$(git lfs env | grep -v "^GIT_EXEC_PATH=")
|
||||||
contains_same_elements "$expected" "$actual"
|
contains_same_elements "$expected" "$actual"
|
||||||
|
|
||||||
cd .git
|
cd .git
|
||||||
expected2=$(echo "$expected" | sed -e 's/LocalWorkingDir=.*/LocalWorkingDir=/')
|
expected2=$(echo "$expected" | sed -e 's/LocalWorkingDir=.*/LocalWorkingDir=/')
|
||||||
actual2=$(git lfs env)
|
actual2=$(git lfs env | grep -v "^GIT_EXEC_PATH=")
|
||||||
contains_same_elements "$expected2" "$actual2"
|
contains_same_elements "$expected2" "$actual2"
|
||||||
)
|
)
|
||||||
end_test
|
end_test
|
||||||
@ -277,12 +277,12 @@ UploadTransfers=basic
|
|||||||
%s
|
%s
|
||||||
%s
|
%s
|
||||||
' "$(git lfs version)" "$(git version)" "$endpoint" "$localwd" "$localgit" "$localgitstore" "$localmedia" "$tempdir" "$lfsstorage" "$envVars" "$envInitConfig")
|
' "$(git lfs version)" "$(git version)" "$endpoint" "$localwd" "$localgit" "$localgitstore" "$localmedia" "$tempdir" "$lfsstorage" "$envVars" "$envInitConfig")
|
||||||
actual=$(git lfs env)
|
actual=$(git lfs env | grep -v "^GIT_EXEC_PATH=")
|
||||||
contains_same_elements "$expected" "$actual"
|
contains_same_elements "$expected" "$actual"
|
||||||
|
|
||||||
cd .git
|
cd .git
|
||||||
expected2=$(echo "$expected" | sed -e 's/LocalWorkingDir=.*/LocalWorkingDir=/')
|
expected2=$(echo "$expected" | sed -e 's/LocalWorkingDir=.*/LocalWorkingDir=/')
|
||||||
actual2=$(git lfs env)
|
actual2=$(git lfs env | grep -v "^GIT_EXEC_PATH=")
|
||||||
contains_same_elements "$expected2" "$actual2"
|
contains_same_elements "$expected2" "$actual2"
|
||||||
)
|
)
|
||||||
end_test
|
end_test
|
||||||
@ -337,12 +337,12 @@ UploadTransfers=basic
|
|||||||
%s
|
%s
|
||||||
%s
|
%s
|
||||||
' "$(git lfs version)" "$(git version)" "$localwd" "$localgit" "$localgitstore" "$localmedia" "$tempdir" "$lfsstorage" "$envVars" "$envInitConfig")
|
' "$(git lfs version)" "$(git version)" "$localwd" "$localgit" "$localgitstore" "$localmedia" "$tempdir" "$lfsstorage" "$envVars" "$envInitConfig")
|
||||||
actual=$(git lfs env)
|
actual=$(git lfs env | grep -v "^GIT_EXEC_PATH=")
|
||||||
contains_same_elements "$expected" "$actual"
|
contains_same_elements "$expected" "$actual"
|
||||||
|
|
||||||
cd .git
|
cd .git
|
||||||
expected2=$(echo "$expected" | sed -e 's/LocalWorkingDir=.*/LocalWorkingDir=/')
|
expected2=$(echo "$expected" | sed -e 's/LocalWorkingDir=.*/LocalWorkingDir=/')
|
||||||
actual2=$(git lfs env)
|
actual2=$(git lfs env | grep -v "^GIT_EXEC_PATH=")
|
||||||
contains_same_elements "$expected2" "$actual2"
|
contains_same_elements "$expected2" "$actual2"
|
||||||
)
|
)
|
||||||
end_test
|
end_test
|
||||||
@ -398,12 +398,12 @@ UploadTransfers=basic
|
|||||||
%s
|
%s
|
||||||
%s
|
%s
|
||||||
' "$(git lfs version)" "$(git version)" "$localwd" "$localgit" "$localgitstore" "$localmedia" "$tempdir" "$lfsstorage" "$envVars" "$envInitConfig")
|
' "$(git lfs version)" "$(git version)" "$localwd" "$localgit" "$localgitstore" "$localmedia" "$tempdir" "$lfsstorage" "$envVars" "$envInitConfig")
|
||||||
actual=$(git lfs env)
|
actual=$(git lfs env | grep -v "^GIT_EXEC_PATH=")
|
||||||
contains_same_elements "$expected" "$actual"
|
contains_same_elements "$expected" "$actual"
|
||||||
|
|
||||||
cd .git
|
cd .git
|
||||||
expected2=$(echo "$expected" | sed -e 's/LocalWorkingDir=.*/LocalWorkingDir=/')
|
expected2=$(echo "$expected" | sed -e 's/LocalWorkingDir=.*/LocalWorkingDir=/')
|
||||||
actual2=$(git lfs env)
|
actual2=$(git lfs env | grep -v "^GIT_EXEC_PATH=")
|
||||||
contains_same_elements "$expected2" "$actual2"
|
contains_same_elements "$expected2" "$actual2"
|
||||||
)
|
)
|
||||||
end_test
|
end_test
|
||||||
@ -466,12 +466,12 @@ UploadTransfers=basic
|
|||||||
%s
|
%s
|
||||||
%s
|
%s
|
||||||
' "$(git lfs version)" "$(git version)" "$localwd" "$localgit" "$localgitstore" "$localmedia" "$tempdir" "$lfsstorage" "$envVars" "$envInitConfig")
|
' "$(git lfs version)" "$(git version)" "$localwd" "$localgit" "$localgitstore" "$localmedia" "$tempdir" "$lfsstorage" "$envVars" "$envInitConfig")
|
||||||
actual=$(git lfs env)
|
actual=$(git lfs env | grep -v "^GIT_EXEC_PATH=")
|
||||||
contains_same_elements "$expected" "$actual"
|
contains_same_elements "$expected" "$actual"
|
||||||
|
|
||||||
mkdir a
|
mkdir a
|
||||||
cd a
|
cd a
|
||||||
actual2=$(git lfs env)
|
actual2=$(git lfs env | grep -v "^GIT_EXEC_PATH=")
|
||||||
contains_same_elements "$expected" "$actual2"
|
contains_same_elements "$expected" "$actual2"
|
||||||
)
|
)
|
||||||
end_test
|
end_test
|
||||||
@ -522,19 +522,23 @@ UploadTransfers=basic
|
|||||||
%s
|
%s
|
||||||
' "$(git lfs version)" "$(git version)" "$localwd" "$localgit" "$localgitstore" "$localmedia" "$tempdir" "$lfsstorage" "$envVars" "$envInitConfig")
|
' "$(git lfs version)" "$(git version)" "$localwd" "$localgit" "$localgitstore" "$localmedia" "$tempdir" "$lfsstorage" "$envVars" "$envInitConfig")
|
||||||
|
|
||||||
actual=$(GIT_DIR=$gitDir GIT_WORK_TREE=$workTree git lfs env)
|
actual=$(GIT_DIR=$gitDir GIT_WORK_TREE=$workTree git lfs env \
|
||||||
|
| grep -v "^GIT_EXEC_PATH=")
|
||||||
contains_same_elements "$expected" "$actual"
|
contains_same_elements "$expected" "$actual"
|
||||||
|
|
||||||
cd $TRASHDIR/$reponame
|
cd $TRASHDIR/$reponame
|
||||||
actual2=$(GIT_DIR=$gitDir GIT_WORK_TREE=$workTree git lfs env)
|
actual2=$(GIT_DIR=$gitDir GIT_WORK_TREE=$workTree git lfs env \
|
||||||
|
| grep -v "^GIT_EXEC_PATH=")
|
||||||
contains_same_elements "$expected" "$actual2"
|
contains_same_elements "$expected" "$actual2"
|
||||||
|
|
||||||
cd $TRASHDIR/$reponame/.git
|
cd $TRASHDIR/$reponame/.git
|
||||||
actual3=$(GIT_DIR=$gitDir GIT_WORK_TREE=$workTree git lfs env)
|
actual3=$(GIT_DIR=$gitDir GIT_WORK_TREE=$workTree git lfs env \
|
||||||
|
| grep -v "^GIT_EXEC_PATH=")
|
||||||
contains_same_elements "$expected" "$actual3"
|
contains_same_elements "$expected" "$actual3"
|
||||||
|
|
||||||
cd $TRASHDIR/$reponame/a/b/c
|
cd $TRASHDIR/$reponame/a/b/c
|
||||||
actual4=$(GIT_DIR=$gitDir GIT_WORK_TREE=$workTree git lfs env)
|
actual4=$(GIT_DIR=$gitDir GIT_WORK_TREE=$workTree git lfs env \
|
||||||
|
| grep -v "^GIT_EXEC_PATH=")
|
||||||
contains_same_elements "$expected" "$actual4"
|
contains_same_elements "$expected" "$actual4"
|
||||||
|
|
||||||
envVars="$(GIT_DIR=$gitDir GIT_WORK_TREE=a/b env | grep "^GIT" | sort)"
|
envVars="$(GIT_DIR=$gitDir GIT_WORK_TREE=a/b env | grep "^GIT" | sort)"
|
||||||
@ -565,7 +569,8 @@ DownloadTransfers=basic
|
|||||||
UploadTransfers=basic
|
UploadTransfers=basic
|
||||||
%s
|
%s
|
||||||
' "$(git lfs version)" "$(git version)" "$localwd" "$localgit" "$localgitstore" "$localmedia" "$tempdir" "$lfsstorage" "$envVars")
|
' "$(git lfs version)" "$(git version)" "$localwd" "$localgit" "$localgitstore" "$localmedia" "$tempdir" "$lfsstorage" "$envVars")
|
||||||
actual5=$(GIT_DIR=$gitDir GIT_WORK_TREE=a/b git lfs env)
|
actual5=$(GIT_DIR=$gitDir GIT_WORK_TREE=a/b git lfs env \
|
||||||
|
| grep -v "^GIT_EXEC_PATH=")
|
||||||
contains_same_elements "$expected5" "$actual5"
|
contains_same_elements "$expected5" "$actual5"
|
||||||
|
|
||||||
cd $TRASHDIR/$reponame/a/b
|
cd $TRASHDIR/$reponame/a/b
|
||||||
@ -598,7 +603,7 @@ UploadTransfers=basic
|
|||||||
%s
|
%s
|
||||||
%s
|
%s
|
||||||
' "$(git lfs version)" "$(git version)" "$localwd" "$localgit" "$localgitstore" "$localmedia" "$tempdir" "$lfsstorage" "$envVars" "$envInitConfig")
|
' "$(git lfs version)" "$(git version)" "$localwd" "$localgit" "$localgitstore" "$localmedia" "$tempdir" "$lfsstorage" "$envVars" "$envInitConfig")
|
||||||
actual7=$(GIT_DIR=$gitDir git lfs env)
|
actual7=$(GIT_DIR=$gitDir git lfs env | grep -v "^GIT_EXEC_PATH=")
|
||||||
contains_same_elements "$expected7" "$actual7"
|
contains_same_elements "$expected7" "$actual7"
|
||||||
|
|
||||||
cd $TRASHDIR/$reponame/a
|
cd $TRASHDIR/$reponame/a
|
||||||
@ -631,7 +636,7 @@ UploadTransfers=basic
|
|||||||
%s
|
%s
|
||||||
%s
|
%s
|
||||||
' "$(git lfs version)" "$(git version)" "$localwd" "$localgit" "$localgitstore" "$localmedia" "$tempdir" "$lfsstorage" "$envVars" "$envInitConfig")
|
' "$(git lfs version)" "$(git version)" "$localwd" "$localgit" "$localgitstore" "$localmedia" "$tempdir" "$lfsstorage" "$envVars" "$envInitConfig")
|
||||||
actual8=$(GIT_WORK_TREE=$workTree git lfs env)
|
actual8=$(GIT_WORK_TREE=$workTree git lfs env | grep -v "^GIT_EXEC_PATH=")
|
||||||
contains_same_elements "$expected8" "$actual8"
|
contains_same_elements "$expected8" "$actual8"
|
||||||
)
|
)
|
||||||
end_test
|
end_test
|
||||||
@ -676,7 +681,7 @@ UploadTransfers=basic
|
|||||||
%s
|
%s
|
||||||
%s
|
%s
|
||||||
" "$(git lfs version)" "$(git version)" "$localgit" "$localgitstore" "$localmedia" "$tempdir" "$lfsstorage" "$envVars" "$envInitConfig")
|
" "$(git lfs version)" "$(git version)" "$localgit" "$localgitstore" "$localmedia" "$tempdir" "$lfsstorage" "$envVars" "$envInitConfig")
|
||||||
actual=$(git lfs env)
|
actual=$(git lfs env | grep -v "^GIT_EXEC_PATH=")
|
||||||
contains_same_elements "$expected" "$actual"
|
contains_same_elements "$expected" "$actual"
|
||||||
|
|
||||||
)
|
)
|
||||||
@ -698,7 +703,8 @@ Endpoint (other)=https://other-git-server.com/user/repo.git/info/lfs (auth=none)
|
|||||||
SSH=git@other-git-server.com:user/repo.git
|
SSH=git@other-git-server.com:user/repo.git
|
||||||
GIT_SSH=lfs-ssh-echo'
|
GIT_SSH=lfs-ssh-echo'
|
||||||
|
|
||||||
contains_same_elements "$expected" "$(git lfs env | grep -e "Endpoint" -e "SSH=")"
|
contains_same_elements "$expected" "$(git lfs env \
|
||||||
|
| grep -v "^GIT_EXEC_PATH=" | grep -e "Endpoint" -e "SSH=")"
|
||||||
)
|
)
|
||||||
end_test
|
end_test
|
||||||
|
|
||||||
@ -754,7 +760,7 @@ UploadTransfers=basic
|
|||||||
%s
|
%s
|
||||||
%s
|
%s
|
||||||
' "$(git lfs version)" "$(git version)" "$localwd" "$localgit" "$localgitstore" "$localmedia" "$tempdir" "$lfsstorage" "$envVars" "$envInitConfig")
|
' "$(git lfs version)" "$(git version)" "$localwd" "$localgit" "$localgitstore" "$localmedia" "$tempdir" "$lfsstorage" "$envVars" "$envInitConfig")
|
||||||
actual=$(git lfs env)
|
actual=$(git lfs env | grep -v "^GIT_EXEC_PATH=")
|
||||||
contains_same_elements "$expectedenabled" "$actual"
|
contains_same_elements "$expectedenabled" "$actual"
|
||||||
|
|
||||||
git config --unset lfs.skipdownloaderrors
|
git config --unset lfs.skipdownloaderrors
|
||||||
@ -787,11 +793,11 @@ UploadTransfers=basic
|
|||||||
%s
|
%s
|
||||||
%s
|
%s
|
||||||
' "$(git lfs version)" "$(git version)" "$localwd" "$localgit" "$localgitstore" "$localmedia" "$tempdir" "$lfsstorage" "$envVars" "$envInitConfig")
|
' "$(git lfs version)" "$(git version)" "$localwd" "$localgit" "$localgitstore" "$localmedia" "$tempdir" "$lfsstorage" "$envVars" "$envInitConfig")
|
||||||
actual=$(git lfs env)
|
actual=$(git lfs env | grep -v "^GIT_EXEC_PATH=")
|
||||||
contains_same_elements "$expecteddisabled" "$actual"
|
contains_same_elements "$expecteddisabled" "$actual"
|
||||||
|
|
||||||
# now enable via env var
|
# now enable via env var
|
||||||
actual=$(GIT_LFS_SKIP_DOWNLOAD_ERRORS=1 git lfs env)
|
actual=$(GIT_LFS_SKIP_DOWNLOAD_ERRORS=1 git lfs env | grep -v "^GIT_EXEC_PATH=")
|
||||||
contains_same_elements "$expectedenabled" "$actual"
|
contains_same_elements "$expectedenabled" "$actual"
|
||||||
|
|
||||||
|
|
||||||
@ -853,7 +859,7 @@ UploadTransfers=basic,supertransfer,tus
|
|||||||
%s
|
%s
|
||||||
%s
|
%s
|
||||||
' "$(git lfs version)" "$(git version)" "$localwd" "$localgit" "$localgitstore" "$localmedia" "$tempdir" "$lfsstorage" "$envVars" "$envInitConfig")
|
' "$(git lfs version)" "$(git version)" "$localwd" "$localgit" "$localgitstore" "$localmedia" "$tempdir" "$lfsstorage" "$envVars" "$envInitConfig")
|
||||||
actual=$(git lfs env)
|
actual=$(git lfs env | grep -v "^GIT_EXEC_PATH=")
|
||||||
contains_same_elements "$expectedenabled" "$actual"
|
contains_same_elements "$expectedenabled" "$actual"
|
||||||
|
|
||||||
)
|
)
|
||||||
|
@ -34,7 +34,7 @@ begin_test "http.<url>.extraHeader with authorization"
|
|||||||
setup_remote_repo "$reponame"
|
setup_remote_repo "$reponame"
|
||||||
clone_repo "$reponame" "$reponame"
|
clone_repo "$reponame" "$reponame"
|
||||||
|
|
||||||
# See: test/cmd/lfstest-gitserver.go:1176.
|
# See: test/cmd/lfstest-gitserver.go:missingRequiredCreds().
|
||||||
user="requirecreds"
|
user="requirecreds"
|
||||||
pass="pass"
|
pass="pass"
|
||||||
auth="Basic $(echo -n $user:$pass | base64)"
|
auth="Basic $(echo -n $user:$pass | base64)"
|
||||||
@ -59,3 +59,40 @@ begin_test "http.<url>.extraHeader with authorization"
|
|||||||
[ "0" -eq "$(grep -c "creds: git credential reject" curl.log)" ]
|
[ "0" -eq "$(grep -c "creds: git credential reject" curl.log)" ]
|
||||||
)
|
)
|
||||||
end_test
|
end_test
|
||||||
|
|
||||||
|
begin_test "http.<url>.extraHeader with authorization (casing)"
|
||||||
|
(
|
||||||
|
set -e
|
||||||
|
|
||||||
|
reponame="requirecreds-extraHeaderCasing"
|
||||||
|
setup_remote_repo "$reponame"
|
||||||
|
clone_repo "$reponame" "$reponame"
|
||||||
|
|
||||||
|
# See: test/cmd/lfstest-gitserver.go:missingRequiredCreds().
|
||||||
|
user="requirecreds"
|
||||||
|
pass="pass"
|
||||||
|
auth="Basic $(echo -n $user:$pass | base64)"
|
||||||
|
|
||||||
|
git config --local --add lfs.access basic
|
||||||
|
# N.B.: "AUTHORIZATION" is not the correct casing, and is therefore the
|
||||||
|
# subject of this test. See lfsapi.Client.extraHeaders() for more.
|
||||||
|
git config --local --add "http.extraHeader" "AUTHORIZATION: $auth"
|
||||||
|
|
||||||
|
git lfs track "*.dat"
|
||||||
|
printf "contents" > a.dat
|
||||||
|
git add .gitattributes a.dat
|
||||||
|
git commit -m "initial commit"
|
||||||
|
|
||||||
|
git push origin master 2>&1 | tee curl.log
|
||||||
|
if [ "0" -ne "${PIPESTATUS[0]}" ]; then
|
||||||
|
echo >&2 "expected \`git push origin master\` to succeed, didn't"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
[ "0" -eq "$(grep -c "creds: filling with GIT_ASKPASS" curl.log)" ]
|
||||||
|
[ "0" -eq "$(grep -c "creds: git credential approve" curl.log)" ]
|
||||||
|
[ "0" -eq "$(grep -c "creds: git credential cache" curl.log)" ]
|
||||||
|
[ "0" -eq "$(grep -c "creds: git credential fill" curl.log)" ]
|
||||||
|
[ "0" -eq "$(grep -c "creds: git credential reject" curl.log)" ]
|
||||||
|
)
|
||||||
|
end_test
|
||||||
|
@ -4,17 +4,22 @@
|
|||||||
|
|
||||||
begin_test "install again"
|
begin_test "install again"
|
||||||
(
|
(
|
||||||
set -e
|
set -eo pipefail
|
||||||
|
|
||||||
smudge="$(git config filter.lfs.smudge)"
|
smudge="$(git config filter.lfs.smudge)"
|
||||||
clean="$(git config filter.lfs.clean)"
|
clean="$(git config filter.lfs.clean)"
|
||||||
filter="$(git config filter.lfs.process)"
|
filter="$(git config filter.lfs.process)"
|
||||||
|
|
||||||
printf "$smudge" | grep "git-lfs smudge"
|
[ "$smudge" = "git-lfs smudge -- %f" ]
|
||||||
printf "$clean" | grep "git-lfs clean"
|
[ "$clean" = "git-lfs clean -- %f" ]
|
||||||
printf "$filter" | grep "git-lfs filter-process"
|
[ "$filter" = "git-lfs filter-process" ]
|
||||||
|
|
||||||
git lfs install
|
GIT_TRACE=1 git lfs install --skip-repo 2>&1 | tee install.log
|
||||||
|
|
||||||
|
if grep -q "--replace-all" install.log; then
|
||||||
|
echo >&2 "fatal: unexpected git config --replace-all via 'git lfs install'"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
[ "$smudge" = "$(git config filter.lfs.smudge)" ]
|
[ "$smudge" = "$(git config filter.lfs.smudge)" ]
|
||||||
[ "$clean" = "$(git config filter.lfs.clean)" ]
|
[ "$clean" = "$(git config filter.lfs.clean)" ]
|
||||||
|
@ -12,7 +12,7 @@ begin_test "lock with good ref"
|
|||||||
|
|
||||||
git lfs lock "a.dat" --json 2>&1 | tee lock.json
|
git lfs lock "a.dat" --json 2>&1 | tee lock.json
|
||||||
if [ "0" -ne "${PIPESTATUS[0]}" ]; then
|
if [ "0" -ne "${PIPESTATUS[0]}" ]; then
|
||||||
echo >&2 "fatal: expected 'git lfs lock \'a.dat\'' to succeed"
|
echo >&2 "fatal: expected \'git lfs lock \'a.dat\'\' to succeed"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@ -40,7 +40,7 @@ begin_test "lock with good tracked ref"
|
|||||||
|
|
||||||
git lfs lock "a.dat" --json 2>&1 | tee lock.json
|
git lfs lock "a.dat" --json 2>&1 | tee lock.json
|
||||||
if [ "0" -ne "${PIPESTATUS[0]}" ]; then
|
if [ "0" -ne "${PIPESTATUS[0]}" ]; then
|
||||||
echo >&2 "fatal: expected 'git lfs lock \'a.dat\'' to succeed"
|
echo >&2 "fatal: expected \'git lfs lock \'a.dat\'\' to succeed"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@ -65,7 +65,7 @@ begin_test "lock with bad ref"
|
|||||||
|
|
||||||
GIT_CURL_VERBOSE=1 git lfs lock "a.dat" 2>&1 | tee lock.json
|
GIT_CURL_VERBOSE=1 git lfs lock "a.dat" 2>&1 | tee lock.json
|
||||||
if [ "0" -eq "${PIPESTATUS[0]}" ]; then
|
if [ "0" -eq "${PIPESTATUS[0]}" ]; then
|
||||||
echo >&2 "fatal: expected 'git lfs lock \'a.dat\'' to fail"
|
echo >&2 "fatal: expected \'git lfs lock \'a.dat\'\' to fail"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@ -187,7 +187,7 @@ begin_test "creating a lock (within subdirectory)"
|
|||||||
|
|
||||||
git lfs lock --json "a.dat" | tee lock.json
|
git lfs lock --json "a.dat" | tee lock.json
|
||||||
if [ "0" -ne "${PIPESTATUS[0]}" ]; then
|
if [ "0" -ne "${PIPESTATUS[0]}" ]; then
|
||||||
echo >&2 "fatal: expected 'git lfs lock \'a.dat\'' to succeed"
|
echo >&2 "fatal: expected \'git lfs lock \'a.dat\'\' to succeed"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@ -195,3 +195,37 @@ begin_test "creating a lock (within subdirectory)"
|
|||||||
assert_server_lock "$reponame" "$id"
|
assert_server_lock "$reponame" "$id"
|
||||||
)
|
)
|
||||||
end_test
|
end_test
|
||||||
|
|
||||||
|
begin_test "creating a lock (symlinked working directory)"
|
||||||
|
(
|
||||||
|
set -eo pipefail
|
||||||
|
|
||||||
|
if [[ $(uname) == *"MINGW"* ]]; then
|
||||||
|
echo >&2 "info: skipped on Windows ..."
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
reponame="lock-in-symlinked-working-directory"
|
||||||
|
setup_remote_repo "$reponame"
|
||||||
|
clone_repo "$reponame" "$reponame"
|
||||||
|
|
||||||
|
git lfs track -l "*.dat"
|
||||||
|
mkdir -p folder1 folder2
|
||||||
|
printf "hello" > folder2/a.dat
|
||||||
|
add_symlink "../folder2" "folder1/folder2"
|
||||||
|
|
||||||
|
git add --all .
|
||||||
|
git commit -m "initial commit"
|
||||||
|
git push origin master
|
||||||
|
|
||||||
|
pushd "$TRASHDIR" > /dev/null
|
||||||
|
ln -s "$reponame" "$reponame-symlink"
|
||||||
|
cd "$reponame-symlink"
|
||||||
|
|
||||||
|
git lfs lock --json folder1/folder2/a.dat 2>&1 | tee lock.json
|
||||||
|
|
||||||
|
id="$(assert_lock lock.json folder1/folder2/a.dat)"
|
||||||
|
assert_server_lock "$reponame" "$id" master
|
||||||
|
popd > /dev/null
|
||||||
|
)
|
||||||
|
end_test
|
||||||
|
51
test/test-mergetool.sh
Executable file
51
test/test-mergetool.sh
Executable file
@ -0,0 +1,51 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
. "test/testlib.sh"
|
||||||
|
|
||||||
|
begin_test "mergetool works with large files"
|
||||||
|
(
|
||||||
|
set -e
|
||||||
|
|
||||||
|
reponame="mergetool-works-with-large-files"
|
||||||
|
git init "$reponame"
|
||||||
|
cd "$reponame"
|
||||||
|
|
||||||
|
git lfs track "*.dat"
|
||||||
|
printf "base" > conflict.dat
|
||||||
|
git add .gitattributes conflict.dat
|
||||||
|
git commit -m "initial commit"
|
||||||
|
|
||||||
|
git checkout -b conflict
|
||||||
|
printf "b" > conflict.dat
|
||||||
|
git add conflict.dat
|
||||||
|
git commit -m "conflict.dat: b"
|
||||||
|
|
||||||
|
git checkout master
|
||||||
|
|
||||||
|
printf "a" > conflict.dat
|
||||||
|
git add conflict.dat
|
||||||
|
git commit -m "conflict.dat: a"
|
||||||
|
|
||||||
|
set +e
|
||||||
|
git merge conflict
|
||||||
|
set -e
|
||||||
|
|
||||||
|
git config mergetool.inspect.cmd '
|
||||||
|
for i in BASE LOCAL REMOTE; do
|
||||||
|
echo "\$$i=$(eval "cat \"\$$i\"")";
|
||||||
|
done;
|
||||||
|
exit 1
|
||||||
|
'
|
||||||
|
git config mergetool.inspect.trustExitCode true
|
||||||
|
|
||||||
|
yes | git mergetool \
|
||||||
|
--no-prompt \
|
||||||
|
--tool=inspect \
|
||||||
|
-- conflict.dat 2>&1 \
|
||||||
|
| tee mergetool.log
|
||||||
|
|
||||||
|
grep "\$BASE=base" mergetool.log
|
||||||
|
grep "\$LOCAL=a" mergetool.log
|
||||||
|
grep "\$REMOTE=b" mergetool.log
|
||||||
|
)
|
||||||
|
end_test
|
@ -18,7 +18,7 @@ assert_ref_unmoved() {
|
|||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
# setup_multiple_local_branches creates a repository as follows:
|
# setup_local_branch_with_gitattrs creates a repository as follows:
|
||||||
#
|
#
|
||||||
# A---B
|
# A---B
|
||||||
# \
|
# \
|
||||||
@ -44,6 +44,46 @@ setup_local_branch_with_gitattrs() {
|
|||||||
git commit -m "add .gitattributes"
|
git commit -m "add .gitattributes"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# setup_local_branch_with_nested_gitattrs creates a repository as follows:
|
||||||
|
#
|
||||||
|
# A---B
|
||||||
|
# \
|
||||||
|
# refs/heads/master
|
||||||
|
#
|
||||||
|
# - Commit 'A' has 120, in a.txt, and a corresponding entry in .gitattributes. There is also
|
||||||
|
# 140 in a.md, with no corresponding entry in .gitattributes.
|
||||||
|
# It also has 140 in subtree/a.md, and a corresponding entry in subtree/.gitattributes
|
||||||
|
setup_local_branch_with_nested_gitattrs() {
|
||||||
|
set -e
|
||||||
|
|
||||||
|
reponame="nested-attrs"
|
||||||
|
|
||||||
|
remove_and_create_local_repo "$reponame"
|
||||||
|
|
||||||
|
mkdir b
|
||||||
|
|
||||||
|
base64 < /dev/urandom | head -c 120 > a.txt
|
||||||
|
base64 < /dev/urandom | head -c 140 > a.md
|
||||||
|
base64 < /dev/urandom | head -c 140 > b/a.md
|
||||||
|
|
||||||
|
git add a.txt a.md b/a.md
|
||||||
|
git commit -m "initial commit"
|
||||||
|
|
||||||
|
git lfs track "*.txt"
|
||||||
|
|
||||||
|
git add .gitattributes
|
||||||
|
git commit -m "add .gitattributes"
|
||||||
|
|
||||||
|
cd b
|
||||||
|
|
||||||
|
git lfs track "*.md"
|
||||||
|
|
||||||
|
cd ..
|
||||||
|
|
||||||
|
git add b/.gitattributes
|
||||||
|
git commit -m "add nested .gitattributes"
|
||||||
|
}
|
||||||
|
|
||||||
# setup_multiple_local_branches creates a repository as follows:
|
# setup_multiple_local_branches creates a repository as follows:
|
||||||
#
|
#
|
||||||
# B
|
# B
|
||||||
@ -79,6 +119,42 @@ setup_multiple_local_branches() {
|
|||||||
git checkout master
|
git checkout master
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# setup_multiple_local_branches_with_gitattrs creates a repository in the same way
|
||||||
|
# as setup_multiple_local_branches, but also adds relevant lfs filters to the
|
||||||
|
# .gitattributes file in the master branch
|
||||||
|
setup_multiple_local_branches_with_gitattrs() {
|
||||||
|
set -e
|
||||||
|
|
||||||
|
setup_multiple_local_branches
|
||||||
|
|
||||||
|
git lfs track *.txt
|
||||||
|
git lfs track *.md
|
||||||
|
|
||||||
|
git add .gitattributes
|
||||||
|
git commit -m "add .gitattributes"
|
||||||
|
}
|
||||||
|
|
||||||
|
# setup_local_branch_with_space creates a repository as follows:
|
||||||
|
#
|
||||||
|
# A
|
||||||
|
# \
|
||||||
|
# refs/heads/master
|
||||||
|
#
|
||||||
|
# - Commit 'A' has 50 bytes in a file named "a file.txt".
|
||||||
|
setup_local_branch_with_space() {
|
||||||
|
set -e
|
||||||
|
|
||||||
|
reponame="migrate-local-branch-with-space"
|
||||||
|
filename="a file.txt"
|
||||||
|
|
||||||
|
remove_and_create_local_repo "$reponame"
|
||||||
|
|
||||||
|
base64 < /dev/urandom | head -c 50 > "$filename"
|
||||||
|
|
||||||
|
git add "$filename"
|
||||||
|
git commit -m "initial commit"
|
||||||
|
}
|
||||||
|
|
||||||
# setup_single_remote_branch creates a repository as follows:
|
# setup_single_remote_branch creates a repository as follows:
|
||||||
#
|
#
|
||||||
# A---B
|
# A---B
|
||||||
@ -113,6 +189,18 @@ setup_single_remote_branch() {
|
|||||||
git commit -m "add an additional 30, 50 bytes to a.{txt,md}"
|
git commit -m "add an additional 30, 50 bytes to a.{txt,md}"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setup_single_remote_branch_with_gitattrs() {
|
||||||
|
set -e
|
||||||
|
|
||||||
|
setup_single_remote_branch
|
||||||
|
|
||||||
|
git lfs track *.txt
|
||||||
|
git lfs track *.md
|
||||||
|
|
||||||
|
git add .gitattributes
|
||||||
|
git commit -m "add .gitattributes"
|
||||||
|
}
|
||||||
|
|
||||||
# setup_multiple_remote_branches creates a repository as follows:
|
# setup_multiple_remote_branches creates a repository as follows:
|
||||||
#
|
#
|
||||||
# C
|
# C
|
||||||
@ -220,6 +308,31 @@ setup_single_local_branch_with_annotated_tags() {
|
|||||||
git tag "v1.0.0" -m "v1.0.0"
|
git tag "v1.0.0" -m "v1.0.0"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setup_multiple_remotes() {
|
||||||
|
set -e
|
||||||
|
|
||||||
|
reponame="migrate-multiple-remotes"
|
||||||
|
remove_and_create_remote_repo "$reponame"
|
||||||
|
|
||||||
|
forkname="$(git remote -v \
|
||||||
|
| head -n1 \
|
||||||
|
| cut -d ' ' -f 1 \
|
||||||
|
| sed -e 's/^.*\///g')-fork"
|
||||||
|
( setup_remote_repo "$forkname" )
|
||||||
|
|
||||||
|
git remote add fork "$GITSERVER/$forkname"
|
||||||
|
|
||||||
|
base64 < /dev/urandom | head -c 16 > a.txt
|
||||||
|
git add a.txt
|
||||||
|
git commit -m "initial commit"
|
||||||
|
git push origin master
|
||||||
|
|
||||||
|
base64 < /dev/urandom | head -c 16 > a.txt
|
||||||
|
git add a.txt
|
||||||
|
git commit -m "another commit"
|
||||||
|
git push fork master
|
||||||
|
}
|
||||||
|
|
||||||
# setup_single_local_branch_deep_trees creates a repository as follows:
|
# setup_single_local_branch_deep_trees creates a repository as follows:
|
||||||
#
|
#
|
||||||
# A
|
# A
|
||||||
@ -240,6 +353,29 @@ setup_single_local_branch_deep_trees() {
|
|||||||
git commit -m "initial commit"
|
git commit -m "initial commit"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# setup_local_branch_with_symlink creates a repository as follows:
|
||||||
|
#
|
||||||
|
# A
|
||||||
|
# \
|
||||||
|
# refs/heads/master
|
||||||
|
#
|
||||||
|
# - Commit 'A' has 120, in a.txt, and a symbolic link link.txt to a.txt.
|
||||||
|
setup_local_branch_with_symlink() {
|
||||||
|
set -e
|
||||||
|
|
||||||
|
reponame="migrate-single-local-branch-with-symlink"
|
||||||
|
|
||||||
|
remove_and_create_local_repo "$reponame"
|
||||||
|
|
||||||
|
base64 < /dev/urandom | head -c 120 > a.txt
|
||||||
|
|
||||||
|
git add a.txt
|
||||||
|
git commit -m "initial commit"
|
||||||
|
|
||||||
|
add_symlink "a.txt" "link.txt"
|
||||||
|
git commit -m "add symlink"
|
||||||
|
}
|
||||||
|
|
||||||
# make_bare converts the existing full checkout of a repository into a bare one,
|
# make_bare converts the existing full checkout of a repository into a bare one,
|
||||||
# and then `cd`'s into it.
|
# and then `cd`'s into it.
|
||||||
make_bare() {
|
make_bare() {
|
||||||
|
224
test/test-migrate-import-no-rewrite.sh
Executable file
224
test/test-migrate-import-no-rewrite.sh
Executable file
@ -0,0 +1,224 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
. "test/test-migrate-fixtures.sh"
|
||||||
|
. "test/testlib.sh"
|
||||||
|
|
||||||
|
begin_test "migrate import --no-rewrite (default branch)"
|
||||||
|
(
|
||||||
|
set -e
|
||||||
|
|
||||||
|
setup_local_branch_with_gitattrs
|
||||||
|
|
||||||
|
txt_oid="$(calc_oid "$(git cat-file -p :a.txt)")"
|
||||||
|
prev_commit_oid="$(git rev-parse HEAD)"
|
||||||
|
|
||||||
|
git lfs migrate import --no-rewrite *.txt
|
||||||
|
|
||||||
|
# Ensure our desired files were imported into git-lfs
|
||||||
|
assert_pointer "refs/heads/master" "a.txt" "$txt_oid" "120"
|
||||||
|
assert_local_object "$txt_oid" "120"
|
||||||
|
|
||||||
|
# Ensure the git history remained the same
|
||||||
|
new_commit_oid="$(git rev-parse HEAD~1)"
|
||||||
|
if [ "$prev_commit_oid" != "$new_commit_oid" ]; then
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Ensure a new commit was made
|
||||||
|
new_head_oid="$(git rev-parse HEAD)"
|
||||||
|
if [ "$prev_commit_oid" == "$new_oid" ]; then
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Ensure a new commit message was generated based on the list of imported files
|
||||||
|
commit_msg="$(git log -1 --pretty=format:%s)"
|
||||||
|
echo "$commit_msg" | grep -q "a.txt: convert to Git LFS"
|
||||||
|
)
|
||||||
|
end_test
|
||||||
|
|
||||||
|
begin_test "migrate import --no-rewrite (bare repository)"
|
||||||
|
(
|
||||||
|
set -e
|
||||||
|
|
||||||
|
setup_single_remote_branch_with_gitattrs
|
||||||
|
|
||||||
|
prev_commit_oid="$(git rev-parse HEAD)"
|
||||||
|
txt_oid="$(calc_oid "$(git cat-file -p :a.txt)")"
|
||||||
|
md_oid="$(calc_oid "$(git cat-file -p :a.md)")"
|
||||||
|
|
||||||
|
git lfs migrate import --no-rewrite a.txt a.md
|
||||||
|
|
||||||
|
# Ensure our desired files were imported
|
||||||
|
assert_pointer "refs/heads/master" "a.txt" "$txt_oid" "30"
|
||||||
|
assert_pointer "refs/heads/master" "a.md" "$md_oid" "50"
|
||||||
|
|
||||||
|
# Ensure the git history remained the same
|
||||||
|
new_commit_oid="$(git rev-parse HEAD~1)"
|
||||||
|
if [ "$prev_commit_oid" != "$new_commit_oid" ]; then
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Ensure a new commit was made
|
||||||
|
new_head_oid="$(git rev-parse HEAD)"
|
||||||
|
if [ "$prev_commit_oid" == "$new_oid" ]; then
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
)
|
||||||
|
end_test
|
||||||
|
|
||||||
|
begin_test "migrate import --no-rewrite (multiple branches)"
|
||||||
|
(
|
||||||
|
set -e
|
||||||
|
|
||||||
|
setup_multiple_local_branches_with_gitattrs
|
||||||
|
|
||||||
|
prev_commit_oid="$(git rev-parse HEAD)"
|
||||||
|
|
||||||
|
md_oid="$(calc_oid "$(git cat-file -p :a.md)")"
|
||||||
|
txt_oid="$(calc_oid "$(git cat-file -p :a.txt)")"
|
||||||
|
md_feature_oid="$(calc_oid "$(git cat-file -p my-feature:a.md)")"
|
||||||
|
|
||||||
|
git lfs migrate import --no-rewrite *.txt *.md
|
||||||
|
|
||||||
|
# Ensure our desired files were imported
|
||||||
|
assert_pointer "refs/heads/master" "a.md" "$md_oid" "140"
|
||||||
|
assert_pointer "refs/heads/master" "a.txt" "$txt_oid" "120"
|
||||||
|
|
||||||
|
assert_local_object "$md_oid" "140"
|
||||||
|
assert_local_object "$txt_oid" "120"
|
||||||
|
|
||||||
|
# Ensure our other branch was unmodified
|
||||||
|
refute_local_object "$md_feature_oid" "30"
|
||||||
|
|
||||||
|
# Ensure the git history remained the same
|
||||||
|
new_commit_oid="$(git rev-parse HEAD~1)"
|
||||||
|
if [ "$prev_commit_oid" != "$new_commit_oid" ]; then
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Ensure a new commit was made
|
||||||
|
new_head_oid="$(git rev-parse HEAD)"
|
||||||
|
if [ "$prev_commit_oid" == "$new_oid" ]; then
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
)
|
||||||
|
end_test
|
||||||
|
|
||||||
|
begin_test "migrate import --no-rewrite (no .gitattributes)"
|
||||||
|
(
|
||||||
|
set -e
|
||||||
|
|
||||||
|
setup_multiple_local_branches
|
||||||
|
|
||||||
|
# Ensure command fails if no .gitattributes files are present
|
||||||
|
git lfs migrate import --no-rewrite *.txt *.md 2>&1 | tee migrate.log
|
||||||
|
if [ ${PIPESTATUS[0]} -eq 0 ]; then
|
||||||
|
echo >&2 "fatal: expected git lfs migrate import --no-rewrite to fail, didn't"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
grep "no Git LFS filters found in .gitattributes" migrate.log
|
||||||
|
)
|
||||||
|
end_test
|
||||||
|
|
||||||
|
begin_test "migrate import --no-rewrite (nested .gitattributes)"
|
||||||
|
(
|
||||||
|
set -e
|
||||||
|
|
||||||
|
setup_local_branch_with_nested_gitattrs
|
||||||
|
|
||||||
|
# Ensure a .md filter does not exist in the top-level .gitattributes
|
||||||
|
master_attrs="$(git cat-file -p "$master:.gitattributes")"
|
||||||
|
[ !"$(echo "$master_attrs" | grep -q ".md")" ]
|
||||||
|
|
||||||
|
# Ensure a .md filter exists in the nested .gitattributes
|
||||||
|
nested_attrs="$(git cat-file -p "$master:b/.gitattributes")"
|
||||||
|
echo "$nested_attrs" | grep -q "*.md filter=lfs diff=lfs merge=lfs"
|
||||||
|
|
||||||
|
md_oid="$(calc_oid "$(git cat-file -p :a.md)")"
|
||||||
|
nested_md_oid="$(calc_oid "$(git cat-file -p :b/a.md)")"
|
||||||
|
txt_oid="$(calc_oid "$(git cat-file -p :a.txt)")"
|
||||||
|
|
||||||
|
git lfs migrate import --no-rewrite a.txt b/a.md
|
||||||
|
|
||||||
|
# Ensure a.txt and subtree/a.md were imported, even though *.md only exists in the
|
||||||
|
# nested subtree/.gitattributes file
|
||||||
|
assert_pointer "refs/heads/master" "b/a.md" "$nested_md_oid" "140"
|
||||||
|
assert_pointer "refs/heads/master" "a.txt" "$txt_oid" "120"
|
||||||
|
|
||||||
|
assert_local_object "$nested_md_oid" 140
|
||||||
|
assert_local_object "$txt_oid" 120
|
||||||
|
refute_local_object "$md_oid" 140
|
||||||
|
|
||||||
|
# Failure should occur when trying to import a.md as no entry exists in
|
||||||
|
# top-level .gitattributes file
|
||||||
|
git lfs migrate import --no-rewrite a.md 2>&1 | tee migrate.log
|
||||||
|
if [ ${PIPESTATUS[0]} -eq 0 ]; then
|
||||||
|
echo >&2 "fatal: expected git lfs migrate import --no-rewrite to fail, didn't"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
grep "a.md did not match any Git LFS filters in .gitattributes" migrate.log
|
||||||
|
)
|
||||||
|
end_test
|
||||||
|
|
||||||
|
begin_test "migrate import --no-rewrite (with commit message)"
|
||||||
|
(
|
||||||
|
set -e
|
||||||
|
|
||||||
|
setup_local_branch_with_gitattrs
|
||||||
|
|
||||||
|
prev_commit_oid="$(git rev-parse HEAD)"
|
||||||
|
expected_commit_msg="run git-lfs migrate import --no-rewrite"
|
||||||
|
|
||||||
|
git lfs migrate import --message "$expected_commit_msg" --no-rewrite *.txt
|
||||||
|
|
||||||
|
# Ensure the git history remained the same
|
||||||
|
new_commit_oid="$(git rev-parse HEAD~1)"
|
||||||
|
if [ "$prev_commit_oid" != "$new_commit_oid" ]; then
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Ensure a new commit was made
|
||||||
|
new_head_oid="$(git rev-parse HEAD)"
|
||||||
|
if [ "$prev_commit_oid" == "$new_oid" ]; then
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Ensure the provided commit message was used
|
||||||
|
commit_msg="$(git log -1 --pretty=format:%s)"
|
||||||
|
if [ "$commit_msg" != "$expected_commit_msg" ]; then
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
)
|
||||||
|
end_test
|
||||||
|
|
||||||
|
begin_test "migrate import --no-rewrite (with empty commit message)"
|
||||||
|
(
|
||||||
|
set -e
|
||||||
|
|
||||||
|
setup_local_branch_with_gitattrs
|
||||||
|
|
||||||
|
prev_commit_oid="$(git rev-parse HEAD)"
|
||||||
|
|
||||||
|
git lfs migrate import -m "" --no-rewrite *.txt
|
||||||
|
|
||||||
|
# Ensure the git history remained the same
|
||||||
|
new_commit_oid="$(git rev-parse HEAD~1)"
|
||||||
|
if [ "$prev_commit_oid" != "$new_commit_oid" ]; then
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Ensure a new commit was made
|
||||||
|
new_head_oid="$(git rev-parse HEAD)"
|
||||||
|
if [ "$prev_commit_oid" == "$new_oid" ]; then
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Ensure the provided commit message was used
|
||||||
|
commit_msg="$(git log -1 --pretty=format:%s)"
|
||||||
|
if [ "$commit_msg" != "" ]; then
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
)
|
||||||
|
end_test
|
@ -616,3 +616,94 @@ begin_test "migrate import (handle copies of files)"
|
|||||||
[ "$oid_root" = "$oid_root_after_migration" ]
|
[ "$oid_root" = "$oid_root_after_migration" ]
|
||||||
)
|
)
|
||||||
end_test
|
end_test
|
||||||
|
|
||||||
|
begin_test "migrate import (--object-map)"
|
||||||
|
(
|
||||||
|
set -e
|
||||||
|
|
||||||
|
setup_multiple_local_branches
|
||||||
|
|
||||||
|
output_dir=$(mktemp -d)
|
||||||
|
|
||||||
|
git log --all --pretty='format:%H' > "${output_dir}/old_sha.txt"
|
||||||
|
git lfs migrate import --everything --object-map "${output_dir}/object-map.txt"
|
||||||
|
git log --all --pretty='format:%H' > "${output_dir}/new_sha.txt"
|
||||||
|
paste -d',' "${output_dir}/old_sha.txt" "${output_dir}/new_sha.txt" > "${output_dir}/expected-map.txt"
|
||||||
|
|
||||||
|
diff -u <(sort "${output_dir}/expected-map.txt") <(sort "${output_dir}/object-map.txt")
|
||||||
|
)
|
||||||
|
end_test
|
||||||
|
|
||||||
|
begin_test "migrate import (--include with space)"
|
||||||
|
(
|
||||||
|
set -e
|
||||||
|
|
||||||
|
setup_local_branch_with_space
|
||||||
|
|
||||||
|
oid="$(calc_oid "$(git cat-file -p :"a file.txt")")"
|
||||||
|
|
||||||
|
git lfs migrate import --include "a file.txt"
|
||||||
|
|
||||||
|
assert_pointer "refs/heads/master" "a file.txt" "$oid" 50
|
||||||
|
cat .gitattributes
|
||||||
|
if [ 1 -ne "$(grep -c "a\[\[:space:\]\]file.txt" .gitattributes)" ]; then
|
||||||
|
echo >&2 "fatal: expected \"a[[:space:]]file.txt\" to appear in .gitattributes"
|
||||||
|
echo >&2 "fatal: got"
|
||||||
|
sed -e 's/^/ /g' < .gitattributes >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
)
|
||||||
|
end_test
|
||||||
|
|
||||||
|
begin_test "migrate import (handle symbolic link)"
|
||||||
|
(
|
||||||
|
set -e
|
||||||
|
|
||||||
|
setup_local_branch_with_symlink
|
||||||
|
|
||||||
|
txt_oid="$(calc_oid "$(git cat-file -p :a.txt)")"
|
||||||
|
link_oid="$(calc_oid "$(git cat-file -p :link.txt)")"
|
||||||
|
|
||||||
|
git lfs migrate import --include="*.txt"
|
||||||
|
|
||||||
|
assert_pointer "refs/heads/master" "a.txt" "$txt_oid" "120"
|
||||||
|
|
||||||
|
assert_local_object "$txt_oid" "120"
|
||||||
|
# "link.txt" is a symbolic link so it should be not in LFS
|
||||||
|
refute_local_object "$link_oid" "5"
|
||||||
|
)
|
||||||
|
end_test
|
||||||
|
|
||||||
|
begin_test "migrate import (commit --allow-empty)"
|
||||||
|
(
|
||||||
|
set -e
|
||||||
|
|
||||||
|
reponame="migrate---allow-empty"
|
||||||
|
git init "$reponame"
|
||||||
|
cd "$reponame"
|
||||||
|
|
||||||
|
git commit --allow-empty -m "initial commit"
|
||||||
|
|
||||||
|
original_head="$(git rev-parse HEAD)"
|
||||||
|
git lfs migrate import --everything
|
||||||
|
migrated_head="$(git rev-parse HEAD)"
|
||||||
|
|
||||||
|
assert_ref_unmoved "HEAD" "$original_head" "$migrated_head"
|
||||||
|
)
|
||||||
|
end_test
|
||||||
|
|
||||||
|
begin_test "migrate import (multiple remotes)"
|
||||||
|
(
|
||||||
|
set -e
|
||||||
|
|
||||||
|
setup_multiple_remotes
|
||||||
|
|
||||||
|
original_master="$(git rev-parse master)"
|
||||||
|
|
||||||
|
git lfs migrate import
|
||||||
|
|
||||||
|
migrated_master="$(git rev-parse master)"
|
||||||
|
|
||||||
|
assert_ref_unmoved "master" "$original_master" "$migrated_master"
|
||||||
|
)
|
||||||
|
end_test
|
||||||
|
@ -119,6 +119,34 @@ begin_test "status --json"
|
|||||||
)
|
)
|
||||||
end_test
|
end_test
|
||||||
|
|
||||||
|
begin_test "status in a sub-directory"
|
||||||
|
(
|
||||||
|
set -e
|
||||||
|
|
||||||
|
reponame="status-sub-directory"
|
||||||
|
git init "$reponame"
|
||||||
|
cd "$reponame"
|
||||||
|
|
||||||
|
git lfs track "*.dat"
|
||||||
|
printf "asdf" > file.dat
|
||||||
|
mkdir -p dir
|
||||||
|
git add .gitattributes file.dat
|
||||||
|
git commit -m "initial commit"
|
||||||
|
|
||||||
|
printf "ASDF" > file.dat
|
||||||
|
|
||||||
|
expected="On branch master
|
||||||
|
|
||||||
|
Git LFS objects to be committed:
|
||||||
|
|
||||||
|
|
||||||
|
Git LFS objects not staged for commit:
|
||||||
|
|
||||||
|
../file.dat (LFS: f0e4c2f -> File: 99b3bcf)"
|
||||||
|
|
||||||
|
[ "$expected" = "$(cd dir && git lfs status)" ]
|
||||||
|
)
|
||||||
|
end_test
|
||||||
|
|
||||||
begin_test "status: outside git repository"
|
begin_test "status: outside git repository"
|
||||||
(
|
(
|
||||||
|
@ -540,3 +540,58 @@ begin_test "track (with comments)"
|
|||||||
[ "0" -eq "$(grep -c "\.png" track.log)" ]
|
[ "0" -eq "$(grep -c "\.png" track.log)" ]
|
||||||
)
|
)
|
||||||
end_test
|
end_test
|
||||||
|
|
||||||
|
begin_test "track (with current-directory prefix)"
|
||||||
|
(
|
||||||
|
set -e
|
||||||
|
|
||||||
|
reponame="track-with-current-directory-prefix"
|
||||||
|
git init "$reponame"
|
||||||
|
cd "$reponame"
|
||||||
|
|
||||||
|
git lfs track "./a.dat"
|
||||||
|
printf "a" > a.dat
|
||||||
|
|
||||||
|
git add .gitattributes a.dat
|
||||||
|
git commit -m "initial commit"
|
||||||
|
|
||||||
|
grep -e "^a.dat" .gitattributes
|
||||||
|
)
|
||||||
|
end_test
|
||||||
|
|
||||||
|
begin_test "track (global gitattributes)"
|
||||||
|
(
|
||||||
|
set -e
|
||||||
|
|
||||||
|
reponame="track-global-gitattributes"
|
||||||
|
git init "$reponame"
|
||||||
|
cd "$reponame"
|
||||||
|
|
||||||
|
global="$(cd .. && pwd)/gitattributes-global"
|
||||||
|
|
||||||
|
echo "*.dat filter=lfs diff=lfs merge=lfs -text" > "$global"
|
||||||
|
git config --local core.attributesfile "$global"
|
||||||
|
|
||||||
|
git lfs track 2>&1 | tee track.log
|
||||||
|
grep "*.dat" track.log
|
||||||
|
)
|
||||||
|
end_test
|
||||||
|
|
||||||
|
begin_test "track (system gitattributes)"
|
||||||
|
(
|
||||||
|
set -e
|
||||||
|
|
||||||
|
reponame="track-system-gitattributes"
|
||||||
|
git init "$reponame"
|
||||||
|
cd "$reponame"
|
||||||
|
|
||||||
|
pushd "$TRASHDIR" > /dev/null
|
||||||
|
mkdir -p "prefix/${reponame}/etc"
|
||||||
|
cd "prefix/${reponame}/etc"
|
||||||
|
echo "*.dat filter=lfs diff=lfs merge=lfs -text" > gitattributes
|
||||||
|
popd > /dev/null
|
||||||
|
|
||||||
|
PREFIX="${TRASHDIR}/prefix/${reponame}" git lfs track 2>&1 | tee track.log
|
||||||
|
grep "*.dat" track.log
|
||||||
|
)
|
||||||
|
end_test
|
||||||
|
@ -169,7 +169,12 @@ begin_test "uninstall --local"
|
|||||||
[ "global clean" = "$(git config --global filter.lfs.clean)" ]
|
[ "global clean" = "$(git config --global filter.lfs.clean)" ]
|
||||||
[ "global filter" = "$(git config --global filter.lfs.process)" ]
|
[ "global filter" = "$(git config --global filter.lfs.process)" ]
|
||||||
|
|
||||||
git lfs uninstall --local
|
git lfs uninstall --local 2>&1 | tee uninstall.log
|
||||||
|
if [ ${PIPESTATUS[0]} -ne 0 ]; then
|
||||||
|
echo >&2 "fatal: expected 'git lfs uninstall --local' to succeed"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
grep -v "Global Git LFS configuration has been removed." uninstall.log
|
||||||
|
|
||||||
# global configs
|
# global configs
|
||||||
[ "global smudge" = "$(git config --global filter.lfs.smudge)" ]
|
[ "global smudge" = "$(git config --global filter.lfs.smudge)" ]
|
||||||
|
@ -72,3 +72,65 @@ begin_test "untrack removes escape sequences"
|
|||||||
assert_attributes_count "\\#" "filter=lfs" 0
|
assert_attributes_count "\\#" "filter=lfs" 0
|
||||||
)
|
)
|
||||||
end_test
|
end_test
|
||||||
|
|
||||||
|
begin_test "untrack removes prefixed patterns (legacy)"
|
||||||
|
(
|
||||||
|
set -e
|
||||||
|
|
||||||
|
reponame="untrack-removes-prefix-patterns-legacy"
|
||||||
|
git init "$reponame"
|
||||||
|
cd "$reponame"
|
||||||
|
|
||||||
|
echo "./a.dat filter=lfs diff=lfs merge=lfs" > .gitattributes
|
||||||
|
printf "a" > a.dat
|
||||||
|
git add .gitattributes a.dat
|
||||||
|
git commit -m "initial commit"
|
||||||
|
|
||||||
|
git lfs untrack "./a.dat"
|
||||||
|
|
||||||
|
if [ ! -z "$(cat .gitattributes)" ]; then
|
||||||
|
echo &>2 "fatal: expected 'git lfs untrack' to clear .gitattributes"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
git checkout -- .gitattributes
|
||||||
|
|
||||||
|
git lfs untrack "a.dat"
|
||||||
|
|
||||||
|
if [ ! -z "$(cat .gitattributes)" ]; then
|
||||||
|
echo &>2 "fatal: expected 'git lfs untrack' to clear .gitattributes"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
)
|
||||||
|
end_test
|
||||||
|
|
||||||
|
begin_test "untrack removes prefixed patterns (modern)"
|
||||||
|
(
|
||||||
|
set -e
|
||||||
|
|
||||||
|
reponame="untrack-removes-prefix-patterns-modern"
|
||||||
|
git init "$reponame"
|
||||||
|
cd "$reponame"
|
||||||
|
|
||||||
|
echo "a.dat filter=lfs diff=lfs merge=lfs" > .gitattributes
|
||||||
|
printf "a" > a.dat
|
||||||
|
git add .gitattributes a.dat
|
||||||
|
git commit -m "initial commit"
|
||||||
|
|
||||||
|
git lfs untrack "./a.dat"
|
||||||
|
|
||||||
|
if [ ! -z "$(cat .gitattributes)" ]; then
|
||||||
|
echo &>2 "fatal: expected 'git lfs untrack' to clear .gitattributes"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
git checkout -- .gitattributes
|
||||||
|
|
||||||
|
git lfs untrack "a.dat"
|
||||||
|
|
||||||
|
if [ ! -z "$(cat .gitattributes)" ]; then
|
||||||
|
echo &>2 "fatal: expected 'git lfs untrack' to clear .gitattributes"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
)
|
||||||
|
end_test
|
||||||
|
23
test/test-version.sh
Executable file
23
test/test-version.sh
Executable file
@ -0,0 +1,23 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
. "test/testlib.sh"
|
||||||
|
|
||||||
|
begin_test "git lfs --version is a synonym of git lfs version"
|
||||||
|
(
|
||||||
|
set -e
|
||||||
|
|
||||||
|
reponame="git-lfs-version-synonymous"
|
||||||
|
mkdir "$reponame"
|
||||||
|
cd "$reponame"
|
||||||
|
|
||||||
|
git lfs version 2>&1 >version.log
|
||||||
|
git lfs --version 2>&1 >flag.log
|
||||||
|
|
||||||
|
if [ "$(cat version.log)" != "$(cat flag.log)" ]; then
|
||||||
|
echo >&2 "fatal: expected 'git lfs version' and 'git lfs --version' to"
|
||||||
|
echo >&2 "produce identical output ..."
|
||||||
|
|
||||||
|
diff -u {version,flag}.log
|
||||||
|
fi
|
||||||
|
)
|
||||||
|
end_test
|
@ -46,7 +46,7 @@ UploadTransfers=basic
|
|||||||
$(escape_path "$(env | grep "^GIT")")
|
$(escape_path "$(env | grep "^GIT")")
|
||||||
%s
|
%s
|
||||||
" "$(git lfs version)" "$(git version)" "$envInitConfig")
|
" "$(git lfs version)" "$(git version)" "$envInitConfig")
|
||||||
actual=$(git lfs env)
|
actual=$(git lfs env | grep -v "^GIT_EXEC_PATH=")
|
||||||
contains_same_elements "$expected" "$actual"
|
contains_same_elements "$expected" "$actual"
|
||||||
|
|
||||||
worktreename="worktree-2"
|
worktreename="worktree-2"
|
||||||
@ -82,7 +82,7 @@ UploadTransfers=basic
|
|||||||
$(escape_path "$(env | grep "^GIT")")
|
$(escape_path "$(env | grep "^GIT")")
|
||||||
%s
|
%s
|
||||||
" "$(git lfs version)" "$(git version)" "$envInitConfig")
|
" "$(git lfs version)" "$(git version)" "$envInitConfig")
|
||||||
actual=$(git lfs env)
|
actual=$(git lfs env | grep -v "^GIT_EXEC_PATH=")
|
||||||
contains_same_elements "$expected" "$actual"
|
contains_same_elements "$expected" "$actual"
|
||||||
)
|
)
|
||||||
end_test
|
end_test
|
||||||
|
@ -738,3 +738,14 @@ has_test_dir() {
|
|||||||
exit 0
|
exit 0
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
|
add_symlink() {
|
||||||
|
local src=$1
|
||||||
|
local dest=$2
|
||||||
|
|
||||||
|
prefix=`git rev-parse --show-prefix`
|
||||||
|
hashsrc=`printf "$src" | git hash-object -w --stdin`
|
||||||
|
|
||||||
|
git update-index --add --cacheinfo 120000 "$hashsrc" "$prefix$dest"
|
||||||
|
git checkout -- "$dest"
|
||||||
|
}
|
||||||
|
@ -5,7 +5,6 @@ import (
|
|||||||
"math"
|
"math"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
|
||||||
"sync"
|
"sync"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
"time"
|
"time"
|
||||||
@ -231,12 +230,10 @@ func (m *Meter) skipUpdate() bool {
|
|||||||
|
|
||||||
func (m *Meter) str() string {
|
func (m *Meter) str() string {
|
||||||
// (Uploading|Downloading) LFS objects: 100% (10/10) 100 MiB | 10 MiB/s
|
// (Uploading|Downloading) LFS objects: 100% (10/10) 100 MiB | 10 MiB/s
|
||||||
|
|
||||||
direction := strings.Title(m.Direction.String()) + "ing"
|
|
||||||
percentage := 100 * float64(m.finishedFiles) / float64(m.estimatedFiles)
|
percentage := 100 * float64(m.finishedFiles) / float64(m.estimatedFiles)
|
||||||
|
|
||||||
return fmt.Sprintf("%s LFS objects: %3.f%% (%d/%d), %s | %s",
|
return fmt.Sprintf("%s LFS objects: %3.f%% (%d/%d), %s | %s",
|
||||||
direction,
|
m.Direction.Verb(),
|
||||||
percentage,
|
percentage,
|
||||||
m.finishedFiles, m.estimatedFiles,
|
m.finishedFiles, m.estimatedFiles,
|
||||||
humanize.FormatBytes(clamp(m.currentBytes)),
|
humanize.FormatBytes(clamp(m.currentBytes)),
|
||||||
|
@ -16,10 +16,27 @@ type Direction int
|
|||||||
const (
|
const (
|
||||||
Upload = Direction(iota)
|
Upload = Direction(iota)
|
||||||
Download = Direction(iota)
|
Download = Direction(iota)
|
||||||
|
Checkout = Direction(iota)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Verb returns a string containing the verb form of the receiving action.
|
||||||
|
func (d Direction) Verb() string {
|
||||||
|
switch d {
|
||||||
|
case Checkout:
|
||||||
|
return "Checking out"
|
||||||
|
case Download:
|
||||||
|
return "Downloading"
|
||||||
|
case Upload:
|
||||||
|
return "Uploading"
|
||||||
|
default:
|
||||||
|
return "<unknown>"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (d Direction) String() string {
|
func (d Direction) String() string {
|
||||||
switch d {
|
switch d {
|
||||||
|
case Checkout:
|
||||||
|
return "checkout"
|
||||||
case Download:
|
case Download:
|
||||||
return "download"
|
return "download"
|
||||||
case Upload:
|
case Upload:
|
||||||
|
0
vendor/github.com/bgentry/go-netrc/.hgignore → vendor/github.com/git-lfs/go-netrc/.hgignore
generated
vendored
0
vendor/github.com/bgentry/go-netrc/.hgignore → vendor/github.com/git-lfs/go-netrc/.hgignore
generated
vendored
0
vendor/github.com/bgentry/go-netrc/LICENSE → vendor/github.com/git-lfs/go-netrc/LICENSE
generated
vendored
0
vendor/github.com/bgentry/go-netrc/LICENSE → vendor/github.com/git-lfs/go-netrc/LICENSE
generated
vendored
0
vendor/github.com/bgentry/go-netrc/README.md → vendor/github.com/git-lfs/go-netrc/README.md
generated
vendored
0
vendor/github.com/bgentry/go-netrc/README.md → vendor/github.com/git-lfs/go-netrc/README.md
generated
vendored
0
vendor/github.com/bgentry/go-netrc/netrc/examples/bad_default_order.netrc → vendor/github.com/git-lfs/go-netrc/netrc/examples/bad_default_order.netrc
generated
vendored
0
vendor/github.com/bgentry/go-netrc/netrc/examples/bad_default_order.netrc → vendor/github.com/git-lfs/go-netrc/netrc/examples/bad_default_order.netrc
generated
vendored
6
vendor/github.com/bgentry/go-netrc/netrc/examples/good.netrc → vendor/github.com/git-lfs/go-netrc/netrc/examples/good.netrc
generated
vendored
6
vendor/github.com/bgentry/go-netrc/netrc/examples/good.netrc → vendor/github.com/git-lfs/go-netrc/netrc/examples/good.netrc
generated
vendored
@ -16,6 +16,12 @@ machine ray login demo password mypassword
|
|||||||
|
|
||||||
machine weirdlogin login uname password pass#pass
|
machine weirdlogin login uname password pass#pass
|
||||||
|
|
||||||
|
machine google.com
|
||||||
|
login alice@google.com
|
||||||
|
not-a-keyword
|
||||||
|
password secure
|
||||||
|
also-not-a-keyword
|
||||||
|
|
||||||
default
|
default
|
||||||
login anonymous
|
login anonymous
|
||||||
password joe@example.com
|
password joe@example.com
|
9
vendor/github.com/bgentry/go-netrc/netrc/netrc.go → vendor/github.com/git-lfs/go-netrc/netrc/netrc.go
generated
vendored
9
vendor/github.com/bgentry/go-netrc/netrc/netrc.go → vendor/github.com/git-lfs/go-netrc/netrc/netrc.go
generated
vendored
@ -24,6 +24,7 @@ const (
|
|||||||
tkMacdef
|
tkMacdef
|
||||||
tkComment
|
tkComment
|
||||||
tkWhitespace
|
tkWhitespace
|
||||||
|
tkUnknown
|
||||||
)
|
)
|
||||||
|
|
||||||
var keywords = map[string]tkType{
|
var keywords = map[string]tkType{
|
||||||
@ -70,7 +71,7 @@ func (n *Netrc) MarshalText() (text []byte, err error) {
|
|||||||
// TODO(bgentry): not safe for concurrency
|
// TODO(bgentry): not safe for concurrency
|
||||||
for i := range n.tokens {
|
for i := range n.tokens {
|
||||||
switch n.tokens[i].kind {
|
switch n.tokens[i].kind {
|
||||||
case tkComment, tkDefault, tkWhitespace: // always append these types
|
case tkComment, tkDefault, tkWhitespace, tkUnknown: // always append these types
|
||||||
text = append(text, n.tokens[i].rawkind...)
|
text = append(text, n.tokens[i].rawkind...)
|
||||||
default:
|
default:
|
||||||
if n.tokens[i].value != "" { // skip empty-value tokens
|
if n.tokens[i].value != "" { // skip empty-value tokens
|
||||||
@ -391,9 +392,11 @@ func parse(r io.Reader, pos int) (*Netrc, error) {
|
|||||||
t, err = newToken(rawb)
|
t, err = newToken(rawb)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if currentMacro == nil {
|
if currentMacro == nil {
|
||||||
return nil, &Error{pos, err.Error()}
|
t.kind = tkUnknown
|
||||||
}
|
nrc.tokens = append(nrc.tokens, t)
|
||||||
|
} else {
|
||||||
currentMacro.rawvalue = append(currentMacro.rawvalue, rawb...)
|
currentMacro.rawvalue = append(currentMacro.rawvalue, rawb...)
|
||||||
|
}
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
3
vendor/github.com/bgentry/go-netrc/netrc/netrc_test.go → vendor/github.com/git-lfs/go-netrc/netrc/netrc_test.go
generated
vendored
3
vendor/github.com/bgentry/go-netrc/netrc/netrc_test.go → vendor/github.com/git-lfs/go-netrc/netrc/netrc_test.go
generated
vendored
@ -18,6 +18,7 @@ var expectedMachines = []*Machine{
|
|||||||
&Machine{Name: "mail.google.com", Login: "joe@gmail.com", Password: "somethingSecret", Account: "justagmail"},
|
&Machine{Name: "mail.google.com", Login: "joe@gmail.com", Password: "somethingSecret", Account: "justagmail"},
|
||||||
&Machine{Name: "ray", Login: "demo", Password: "mypassword", Account: ""},
|
&Machine{Name: "ray", Login: "demo", Password: "mypassword", Account: ""},
|
||||||
&Machine{Name: "weirdlogin", Login: "uname", Password: "pass#pass", Account: ""},
|
&Machine{Name: "weirdlogin", Login: "uname", Password: "pass#pass", Account: ""},
|
||||||
|
&Machine{Name: "google.com", Login: "alice@google.com", Password: "secure"},
|
||||||
&Machine{Name: "", Login: "anonymous", Password: "joe@example.com", Account: ""},
|
&Machine{Name: "", Login: "anonymous", Password: "joe@example.com", Account: ""},
|
||||||
}
|
}
|
||||||
var expectedMacros = Macros{
|
var expectedMacros = Macros{
|
||||||
@ -146,7 +147,7 @@ func TestFindMachine(t *testing.T) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
if !eqMachine(m, expectedMachines[3]) {
|
if !eqMachine(m, expectedMachines[4]) {
|
||||||
t.Errorf("bad machine; expected %v, got %v\n", expectedMachines[3], m)
|
t.Errorf("bad machine; expected %v, got %v\n", expectedMachines[3], m)
|
||||||
}
|
}
|
||||||
if !m.IsDefault() {
|
if !m.IsDefault() {
|
Loading…
Reference in New Issue
Block a user