Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions cli/command/image/pull.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,15 @@ type pullOptions struct {
quiet bool
}

// hasTagAndDigest reports whether ref specifies both a tag and a digest.
// Those are valid reference forms, but docker pull treats them as pull-by-digest
// and does not associate the tag with the local image, which is surprising.
func hasTagAndDigest(ref reference.Named) bool {
_, tagged := ref.(reference.Tagged)
_, digested := ref.(reference.Digested)
return tagged && digested
}

// newPullCommand creates a new `docker pull` command
func newPullCommand(dockerCLI command.Cli) *cobra.Command {
var opts pullOptions
Expand Down Expand Up @@ -73,6 +82,10 @@ func runPull(ctx context.Context, dockerCLI command.Cli, opts pullOptions) error
return err
case opts.all && !reference.IsNameOnly(distributionRef):
return errors.New("tag can't be used with --all-tags/-a")
case hasTagAndDigest(distributionRef):
// Use line is NAME[:TAG|@DIGEST]; combining both is ambiguous (tag is
// dropped on pull and the image is not tagged locally).
return errors.New("reference cannot contain both a tag and a digest")
case !opts.all && reference.IsNameOnly(distributionRef):
distributionRef = reference.TagNameOnly(distributionRef)
if tagged, ok := distributionRef.(reference.Tagged); ok && !opts.quiet {
Expand Down
5 changes: 5 additions & 0 deletions cli/command/image/pull_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,11 @@ func TestNewPullCommandErrors(t *testing.T) {
expectedError: "tag can't be used with --all-tags/-a",
args: []string{"--all-tags", "image:tag"},
},
{
name: "tag-and-digest",
expectedError: "reference cannot contain both a tag and a digest",
args: []string{"image:tag@sha256:ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"},
},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
Expand Down
4 changes: 4 additions & 0 deletions docs/reference/commandline/image_pull.md
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,10 @@ Status: Image is up to date for ubuntu@sha256:2e863c44b718727c860746568e1d54afd1
docker.io/library/ubuntu@sha256:2e863c44b718727c860746568e1d54afd13b2fa71b160f5cd9058fc436217b30
```

Do not combine a tag and a digest in the same reference (for example,
`ubuntu:24.04@sha256:…`). `docker pull` rejects that form; use either a tag or
a digest, not both.

Digest can also be used in the `FROM` of a Dockerfile, for example:

```dockerfile
Expand Down