Compare commits

...

No commits in common. "c8" and "c9s" have entirely different histories.
c8 ... c9s

10 changed files with 986 additions and 465 deletions

View File

@ -1,2 +0,0 @@
e76897da8f89170b2e23db7723408a7bdd038ee8 SOURCES/git-lfs-v3.4.1.tar.gz
8f640c97e9736385e8cad79c91c983de895d6053 SOURCES/manpages.tgz

29
.gitignore vendored
View File

@ -1,2 +1,27 @@
SOURCES/git-lfs-v3.4.1.tar.gz
SOURCES/manpages.tgz
/git-lfs-2.2.1.tar.gz
/git-lfs-2.3.4.tar.gz
/git-lfs-2.4.0.tar.gz
/git-lfs-2.4.1.tar.gz
/git-lfs-2.4.2.tar.gz
/git-lfs-2.5.0.tar.gz
/git-lfs-2.5.1.tar.gz
/git-lfs-2.5.2.tar.gz
/git-lfs-2.6.1.tar.gz
/git-lfs-2.7.0.tar.gz
/git-lfs-2.7.1.tar.gz
/git-lfs-2.7.2.tar.gz
/git-lfs-v2.8.0.tar.gz
/git-lfs-v2.9.0.tar.gz
/git-lfs-v2.9.2.tar.gz
/git-lfs-v2.10.0.tar.gz
/git-lfs-v2.11.0.tar.gz
/git-lfs-v2.12.0.tar.gz
/git-lfs-v2.12.1.tar.gz
/git-lfs-v2.13.0.tar.gz
/git-lfs-2.13.3.tar.gz
/git-lfs-v2.13.3.tar.gz
/git-lfs-v3.3.0.tar.gz
/git-lfs-v3.2.0.tar.gz
/git-lfs-v3.4.1.tar.gz
/git-lfs-v3.6.0.tar.gz
/git-lfs-v3.6.1.tar.gz

View File

@ -0,0 +1,757 @@
From 867aa58c816627cbe95f0e38de68daf8cf7cf730 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ond=C5=99ej=20Poho=C5=99elsk=C3=BD?= <opohorel@redhat.com>
Date: Thu, 7 Aug 2025 13:55:34 +0200
Subject: [PATCH] Use constant format string
Resolves build failure with Golang-1.24<
---
commands/command_clean.go | 2 +-
commands/command_dedup.go | 2 +-
commands/command_fsck.go | 4 ++--
commands/command_logs.go | 6 +++---
commands/command_migrate.go | 2 +-
commands/command_migrate_export.go | 4 ++--
commands/command_migrate_import.go | 20 ++++++++++----------
commands/command_migrate_info.go | 6 +++---
commands/command_pointer.go | 2 +-
commands/command_smudge.go | 4 ++--
creds/creds.go | 10 +++++-----
errors/errors.go | 2 +-
errors/types.go | 2 +-
git/githistory/rewriter_test.go | 2 +-
lfs/diff_index_scanner.go | 4 ++--
lfs/gitfilter_smudge.go | 12 ++++++------
lfshttp/certs.go | 12 ++++++------
lfshttp/errors.go | 7 ++++++-
lfshttp/lfshttp.go | 2 +-
lfshttp/standalone/standalone.go | 8 ++++----
ssh/connection.go | 2 +-
t/git-lfs-test-server-api/main.go | 2 +-
tasklog/simple_task.go | 2 +-
tools/filetools.go | 4 ++--
tq/basic_download.go | 4 ++--
tq/basic_upload.go | 4 ++--
tq/custom.go | 2 +-
tq/ssh.go | 6 +++---
tq/transfer_queue.go | 4 ++--
tq/tus_upload.go | 4 ++--
30 files changed, 76 insertions(+), 71 deletions(-)
diff --git a/commands/command_clean.go b/commands/command_clean.go
index 6b02d23c..8fa12d9b 100644
--- a/commands/command_clean.go
+++ b/commands/command_clean.go
@@ -82,7 +82,7 @@ func clean(gf *lfs.GitFilter, to io.Writer, from io.Reader, fileName string, fil
Panic(err, tr.Tr.Get("Unable to move %s to %s", tmpfile, mediafile))
}
- Debug(tr.Tr.Get("Writing %s", mediafile))
+ Debug("%s", tr.Tr.Get("Writing %s", mediafile))
}
_, err = lfs.EncodePointer(to, cleaned.Pointer)
diff --git a/commands/command_dedup.go b/commands/command_dedup.go
index 4d9688f2..2babff45 100644
--- a/commands/command_dedup.go
+++ b/commands/command_dedup.go
@@ -129,7 +129,7 @@ func dedup(p *lfs.WrappedPointer) (success bool, err error) {
if ok, err := tools.CloneFileByPath(dstFile, srcFile); err != nil {
return false, err
} else if !ok {
- return false, errors.Errorf(tr.Tr.Get("unknown clone file error"))
+ return false, errors.Errorf("%s", tr.Tr.Get("unknown clone file error"))
}
// Recover original state
diff --git a/commands/command_fsck.go b/commands/command_fsck.go
index c2332ef8..63756854 100644
--- a/commands/command_fsck.go
+++ b/commands/command_fsck.go
@@ -170,7 +170,7 @@ func doFsckPointers(include, exclude string) []corruptPointer {
var corruptPointers []corruptPointer
gitscanner := lfs.NewGitScanner(cfg, func(p *lfs.WrappedPointer, err error) {
if p != nil {
- Debug(tr.Tr.Get("Examining %v (%v)", p.Oid, p.Name))
+ Debug("%s", tr.Tr.Get("Examining %v (%v)", p.Oid, p.Name))
if !p.Canonical {
cp := corruptPointer{
blobOid: p.Sha1,
@@ -214,7 +214,7 @@ func doFsckPointers(include, exclude string) []corruptPointer {
func fsckPointer(name, oid string, size int64) (bool, error) {
path := cfg.Filesystem().ObjectPathname(oid)
- Debug(tr.Tr.Get("Examining %v (%v)", name, path))
+ Debug("%s", tr.Tr.Get("Examining %v (%v)", name, path))
f, err := os.Open(path)
if pErr, pOk := err.(*os.PathError); pOk {
diff --git a/commands/command_logs.go b/commands/command_logs.go
index 89d738fe..aa781dfa 100644
--- a/commands/command_logs.go
+++ b/commands/command_logs.go
@@ -37,7 +37,7 @@ func logsShowCommand(cmd *cobra.Command, args []string) {
Exit(tr.Tr.Get("Error reading log: %s", name))
}
- Debug(tr.Tr.Get("Reading log: %s", name))
+ Debug("%s", tr.Tr.Get("Reading log: %s", name))
os.Stdout.Write(by)
}
@@ -51,8 +51,8 @@ func logsClearCommand(cmd *cobra.Command, args []string) {
}
func logsBoomtownCommand(cmd *cobra.Command, args []string) {
- Debug(tr.Tr.Get("Sample debug message"))
- err := errors.Wrapf(errors.New(tr.Tr.Get("Sample wrapped error message")), tr.Tr.Get("Sample error message"))
+ Debug("%s", tr.Tr.Get("Sample debug message"))
+ err := errors.Wrapf(errors.New(tr.Tr.Get("Sample wrapped error message")), "%s", tr.Tr.Get("Sample error message"))
Panic(err, tr.Tr.Get("Sample panic message"))
}
diff --git a/commands/command_migrate.go b/commands/command_migrate.go
index e638d0bf..b16680b5 100644
--- a/commands/command_migrate.go
+++ b/commands/command_migrate.go
@@ -319,7 +319,7 @@ func currentRefToMigrate() (*git.Ref, error) {
if current.Type == git.RefTypeOther ||
current.Type == git.RefTypeRemoteBranch {
- return nil, errors.Errorf(tr.Tr.Get("Cannot migrate non-local ref: %s", current.Name))
+ return nil, errors.Errorf("%s", tr.Tr.Get("Cannot migrate non-local ref: %s", current.Name))
}
return current, nil
}
diff --git a/commands/command_migrate_export.go b/commands/command_migrate_export.go
index 16c58653..484134b8 100644
--- a/commands/command_migrate_export.go
+++ b/commands/command_migrate_export.go
@@ -35,7 +35,7 @@ func migrateExportCommand(cmd *cobra.Command, args []string) {
filter := rewriter.Filter()
if len(filter.Include()) <= 0 {
- ExitWithError(errors.Errorf(tr.Tr.Get("One or more files must be specified with --include")))
+ ExitWithError(errors.Errorf("%s", tr.Tr.Get("One or more files must be specified with --include")))
}
tracked := trackedFromExportFilter(filter)
@@ -116,7 +116,7 @@ func migrateExportCommand(cmd *cobra.Command, args []string) {
}
remoteURL := getAPIClient().Endpoints.RemoteEndpoint("download", remote).Url
if remoteURL == "" && cmd.Flag("remote").Changed {
- ExitWithError(errors.Errorf(tr.Tr.Get("Invalid remote %s provided", remote)))
+ ExitWithError(errors.Errorf("%s", tr.Tr.Get("Invalid remote %s provided", remote)))
}
// If we have a valid remote, pre-download all objects using the Transfer Queue
diff --git a/commands/command_migrate_import.go b/commands/command_migrate_import.go
index 8b44b415..b03301f9 100644
--- a/commands/command_migrate_import.go
+++ b/commands/command_migrate_import.go
@@ -44,11 +44,11 @@ func migrateImportCommand(cmd *cobra.Command, args []string) {
if migrateNoRewrite {
if migrateFixup {
- ExitWithError(errors.Errorf(tr.Tr.Get("--no-rewrite and --fixup cannot be combined")))
+ ExitWithError(errors.Errorf("%s", tr.Tr.Get("--no-rewrite and --fixup cannot be combined")))
}
if len(args) == 0 {
- ExitWithError(errors.Errorf(tr.Tr.Get("Expected one or more files with --no-rewrite")))
+ ExitWithError(errors.Errorf("%s", tr.Tr.Get("Expected one or more files with --no-rewrite")))
}
ref, err := git.CurrentRef()
@@ -66,21 +66,21 @@ func migrateImportCommand(cmd *cobra.Command, args []string) {
filter := git.GetAttributeFilter(cfg.LocalWorkingDir(), cfg.LocalGitDir())
if len(filter.Include()) == 0 {
- ExitWithError(errors.Errorf(tr.Tr.Get("No Git LFS filters found in '.gitattributes'")))
+ ExitWithError(errors.Errorf("%s", tr.Tr.Get("No Git LFS filters found in '.gitattributes'")))
}
gf := lfs.NewGitFilter(cfg)
for _, file := range args {
if !filter.Allows(file) {
- ExitWithError(errors.Errorf(tr.Tr.Get("File %s did not match any Git LFS filters in '.gitattributes'", file)))
+ ExitWithError(errors.Errorf("%s", tr.Tr.Get("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, tr.Tr.Get("Could not rewrite %q", file)))
+ ExitWithError(errors.Wrapf(err, "%s", tr.Tr.Get("Could not rewrite %q", file)))
}
}
@@ -124,7 +124,7 @@ func migrateImportCommand(cmd *cobra.Command, args []string) {
if migrateFixup {
include, exclude := getIncludeExcludeArgs(cmd)
if include != nil || exclude != nil {
- ExitWithError(errors.Errorf(tr.Tr.Get("Cannot use --fixup with --include, --exclude")))
+ ExitWithError(errors.Errorf("%s", tr.Tr.Get("Cannot use --fixup with --include, --exclude")))
}
}
@@ -142,7 +142,7 @@ func migrateImportCommand(cmd *cobra.Command, args []string) {
if above > 0 {
include, exclude := getIncludeExcludeArgs(cmd)
if include != nil || exclude != nil || migrateFixup {
- ExitWithError(errors.Errorf(tr.Tr.Get("Cannot use --above with --include, --exclude, --fixup")))
+ ExitWithError(errors.Errorf("%s", tr.Tr.Get("Cannot use --above with --include, --exclude, --fixup")))
}
}
@@ -395,7 +395,7 @@ func rewriteTree(gf *lfs.GitFilter, db *gitobj.ObjectDatabase, root []byte, path
// Try to replace this blob with a Git LFS pointer.
index := findEntry(tree, splits[0])
if index < 0 {
- return nil, errors.Errorf(tr.Tr.Get("unable to find entry %s in tree", splits[0]))
+ return nil, errors.Errorf("%s", tr.Tr.Get("unable to find entry %s in tree", splits[0]))
}
blobEntry := tree.Entries[index]
@@ -433,7 +433,7 @@ func rewriteTree(gf *lfs.GitFilter, db *gitobj.ObjectDatabase, root []byte, path
index := findEntry(tree, head)
if index < 0 {
- return nil, errors.Errorf(tr.Tr.Get("unable to find entry %s in tree", head))
+ return nil, errors.Errorf("%s", tr.Tr.Get("unable to find entry %s in tree", head))
}
subtreeEntry := tree.Entries[index]
@@ -455,7 +455,7 @@ func rewriteTree(gf *lfs.GitFilter, db *gitobj.ObjectDatabase, root []byte, path
return db.WriteTree(tree)
default:
- return nil, errors.Errorf(tr.Tr.Get("error parsing path %s", path))
+ return nil, errors.Errorf("%s", tr.Tr.Get("error parsing path %s", path))
}
}
diff --git a/commands/command_migrate_info.go b/commands/command_migrate_info.go
index bcbc18b2..c0368a6e 100644
--- a/commands/command_migrate_info.go
+++ b/commands/command_migrate_info.go
@@ -96,17 +96,17 @@ func migrateInfoCommand(cmd *cobra.Command, args []string) {
case "ignore":
migrateInfoPointersMode = migrateInfoPointersIgnore
default:
- ExitWithError(errors.Errorf(tr.Tr.Get("Unsupported --pointers option value")))
+ ExitWithError(errors.Errorf("%s", tr.Tr.Get("Unsupported --pointers option value")))
}
}
if migrateFixup {
include, exclude := getIncludeExcludeArgs(cmd)
if include != nil || exclude != nil {
- ExitWithError(errors.Errorf(tr.Tr.Get("Cannot use --fixup with --include, --exclude")))
+ ExitWithError(errors.Errorf("%s", tr.Tr.Get("Cannot use --fixup with --include, --exclude")))
}
if pointers.Changed && migrateInfoPointersMode != migrateInfoPointersIgnore {
- ExitWithError(errors.Errorf(tr.Tr.Get("Cannot use --fixup with --pointers=%s", pointers.Value.String())))
+ ExitWithError(errors.Errorf("%s", tr.Tr.Get("Cannot use --fixup with --pointers=%s", pointers.Value.String())))
}
migrateInfoPointersMode = migrateInfoPointersIgnore
}
diff --git a/commands/command_pointer.go b/commands/command_pointer.go
index a2a57da6..2177408d 100644
--- a/commands/command_pointer.go
+++ b/commands/command_pointer.go
@@ -129,7 +129,7 @@ func pointerCommand(cmd *cobra.Command, args []string) {
os.Exit(1)
}
- fmt.Fprintf(os.Stderr, buf.String())
+ fmt.Fprintf(os.Stderr, "%s", buf.String())
if comparing {
compareOid, err = git.HashObject(bytes.NewReader(buf.Bytes()))
if err != nil {
diff --git a/commands/command_smudge.go b/commands/command_smudge.go
index 0117b996..2b6297c8 100644
--- a/commands/command_smudge.go
+++ b/commands/command_smudge.go
@@ -45,7 +45,7 @@ func delayedSmudge(gf *lfs.GitFilter, s *git.FilterProcessScanner, to io.Writer,
if n != 0 {
return 0, false, nil, errors.NewNotAPointerError(errors.Errorf(
- tr.Tr.Get("Unable to parse pointer at: %q", filename),
+ "%s", tr.Tr.Get("Unable to parse pointer at: %q", filename),
))
}
return 0, false, nil, nil
@@ -108,7 +108,7 @@ func smudge(gf *lfs.GitFilter, to io.Writer, from io.Reader, filename string, sk
if n != 0 {
return 0, errors.NewNotAPointerError(errors.Errorf(
- tr.Tr.Get("Unable to parse pointer at: %q", filename),
+ "%s", tr.Tr.Get("Unable to parse pointer at: %q", filename),
))
}
return 0, nil
diff --git a/creds/creds.go b/creds/creds.go
index 784c1b5f..d869dbca 100644
--- a/creds/creds.go
+++ b/creds/creds.go
@@ -66,13 +66,13 @@ func (c Creds) buffer(protectProtocol bool) (*bytes.Buffer, error) {
for k, v := range c {
for _, item := range v {
if strings.Contains(item, "\n") {
- return nil, errors.Errorf(tr.Tr.Get("credential value for %s contains newline: %q", k, item))
+ return nil, errors.Errorf("%s", tr.Tr.Get("credential value for %s contains newline: %q", k, item))
}
if protectProtocol && strings.Contains(item, "\r") {
- return nil, errors.Errorf(tr.Tr.Get("credential value for %s contains carriage return: %q\nIf this is intended, set `credential.protectProtocol=false`", k, item))
+ return nil, errors.Errorf("%s", tr.Tr.Get("credential value for %s contains carriage return: %q\nIf this is intended, set `credential.protectProtocol=false`", k, item))
}
if strings.Contains(item, string(rune(0))) {
- return nil, errors.Errorf(tr.Tr.Get("credential value for %s contains null byte: %q", k, item))
+ return nil, errors.Errorf("%s", tr.Tr.Get("credential value for %s contains null byte: %q", k, item))
}
buf.Write([]byte(k))
@@ -249,7 +249,7 @@ func (a *AskPassCredentialHelper) getValue(what Creds, valueType credValueType,
case credValueTypePassword:
valueString = "password"
default:
- return "", errors.Errorf(tr.Tr.Get("Invalid Credential type queried from AskPass"))
+ return "", errors.Errorf("%s", tr.Tr.Get("Invalid Credential type queried from AskPass"))
}
// Return the existing credential if it was already provided, otherwise
@@ -274,7 +274,7 @@ func (a *AskPassCredentialHelper) getFromProgram(valueType credValueType, u *url
case credValueTypePassword:
valueString = "Password"
default:
- return "", errors.Errorf(tr.Tr.Get("Invalid Credential type queried from AskPass"))
+ return "", errors.Errorf("%s", tr.Tr.Get("Invalid Credential type queried from AskPass"))
}
// 'cmd' will run the GIT_ASKPASS (or core.askpass) command prompting
diff --git a/errors/errors.go b/errors/errors.go
index dae33a81..c77b5e93 100644
--- a/errors/errors.go
+++ b/errors/errors.go
@@ -114,7 +114,7 @@ func Combine(errs []error) error {
}
buf.WriteString(err.Error())
}
- return fmt.Errorf(buf.String())
+ return fmt.Errorf("%s", buf.String())
}
func Cause(err error) error {
diff --git a/errors/types.go b/errors/types.go
index 041e4f39..b869b4ea 100644
--- a/errors/types.go
+++ b/errors/types.go
@@ -386,7 +386,7 @@ func (e badPointerKeyError) BadPointerKeyError() bool {
}
func NewBadPointerKeyError(expected, actual string) error {
- err := Errorf(tr.Tr.Get("Expected key %s, got %s", expected, actual))
+ err := Errorf("%s", tr.Tr.Get("Expected key %s, got %s", expected, actual))
return badPointerKeyError{expected, actual, newWrappedError(err, tr.Tr.Get("pointer parsing"))}
}
diff --git a/git/githistory/rewriter_test.go b/git/githistory/rewriter_test.go
index 98ce635c..b401e5f3 100644
--- a/git/githistory/rewriter_test.go
+++ b/git/githistory/rewriter_test.go
@@ -377,7 +377,7 @@ func TestHistoryRewriterCallbacksSubtrees(t *testing.T) {
}
func TestHistoryRewriterTreePreCallbackPropagatesErrors(t *testing.T) {
- expected := errors.Errorf("my error")
+ expected := errors.Errorf("%s", "my error")
db := DatabaseFromFixture(t, "linear-history.git")
r := NewRewriter(db)
diff --git a/lfs/diff_index_scanner.go b/lfs/diff_index_scanner.go
index 7ceaf4df..d7029423 100644
--- a/lfs/diff_index_scanner.go
+++ b/lfs/diff_index_scanner.go
@@ -185,12 +185,12 @@ func (s *DiffIndexScanner) scan(line string) (*DiffIndexEntry, error) {
parts := strings.Split(line, "\t")
if len(parts) < 2 {
- return nil, errors.Errorf(tr.Tr.Get("invalid line: %s", line))
+ return nil, errors.Errorf("%s", tr.Tr.Get("invalid line: %s", line))
}
desc := strings.Fields(parts[0])
if len(desc) < 5 {
- return nil, errors.Errorf(tr.Tr.Get("invalid description: %s", parts[0]))
+ return nil, errors.Errorf("%s", tr.Tr.Get("invalid description: %s", parts[0]))
}
entry := &DiffIndexEntry{
diff --git a/lfs/gitfilter_smudge.go b/lfs/gitfilter_smudge.go
index 830e83c4..58049da1 100644
--- a/lfs/gitfilter_smudge.go
+++ b/lfs/gitfilter_smudge.go
@@ -132,7 +132,7 @@ func (f *GitFilter) downloadFile(writer io.Writer, ptr *Pointer, workingfile, me
}
}
- return 0, errors.Wrapf(multiErr, tr.Tr.Get("Error downloading %s (%s)", workingfile, ptr.Oid))
+ return 0, errors.Wrapf(multiErr, "%s", tr.Tr.Get("Error downloading %s (%s)", workingfile, ptr.Oid))
}
return f.readLocalFile(writer, ptr, mediafile, workingfile, nil)
@@ -163,7 +163,7 @@ func (f *GitFilter) downloadFileFallBack(writer io.Writer, ptr *Pointer, working
multiErr = e
}
}
- wrappedError := errors.Wrapf(multiErr, tr.Tr.Get("Error downloading %s (%s)", workingfile, ptr.Oid))
+ wrappedError := errors.Wrapf(multiErr, "%s", tr.Tr.Get("Error downloading %s (%s)", workingfile, ptr.Oid))
if index >= len(remotes)-1 {
return 0, wrappedError
} else {
@@ -176,13 +176,13 @@ func (f *GitFilter) downloadFileFallBack(writer io.Writer, ptr *Pointer, working
return f.readLocalFile(writer, ptr, mediafile, workingfile, nil)
}
}
- return 0, errors.Wrapf(errors.New("No known remotes"), tr.Tr.Get("Error downloading %s (%s)", workingfile, ptr.Oid))
+ return 0, errors.Wrapf(errors.New("No known remotes"), "%s", tr.Tr.Get("Error downloading %s (%s)", workingfile, ptr.Oid))
}
func (f *GitFilter) readLocalFile(writer io.Writer, ptr *Pointer, mediafile string, workingfile string, cb tools.CopyCallback) (int64, error) {
reader, err := tools.RobustOpen(mediafile)
if err != nil {
- return 0, errors.Wrapf(err, tr.Tr.Get("error opening media file"))
+ return 0, errors.Wrapf(err, "%s", tr.Tr.Get("error opening media file"))
}
defer reader.Close()
@@ -250,14 +250,14 @@ func (f *GitFilter) readLocalFile(writer io.Writer, ptr *Pointer, mediafile stri
// setup reader
reader, err = os.Open(response.file.Name())
if err != nil {
- return 0, errors.Wrapf(err, tr.Tr.Get("Error opening smudged file: %s", err))
+ return 0, errors.Wrapf(err, "%s", tr.Tr.Get("Error opening smudged file: %s", err))
}
defer reader.Close()
}
n, err := tools.CopyWithCallback(writer, reader, ptr.Size, cb)
if err != nil {
- return n, errors.Wrapf(err, tr.Tr.Get("Error reading from media file: %s", err))
+ return n, errors.Wrapf(err, "%s", tr.Tr.Get("Error reading from media file: %s", err))
}
return n, nil
diff --git a/lfshttp/certs.go b/lfshttp/certs.go
index c193aa59..68abcb42 100644
--- a/lfshttp/certs.go
+++ b/lfshttp/certs.go
@@ -76,23 +76,23 @@ func getClientCertForHost(c *Client, host string) (*tls.Certificate, error) {
hostSslKey, err := tools.ExpandPath(hostSslKey, false)
if err != nil {
- return nil, errors.Wrapf(err, tr.Tr.Get("Error resolving key path %q", hostSslKey))
+ return nil, errors.Wrapf(err, "%s", tr.Tr.Get("Error resolving key path %q", hostSslKey))
}
hostSslCert, err = tools.ExpandPath(hostSslCert, false)
if err != nil {
- return nil, errors.Wrapf(err, tr.Tr.Get("Error resolving cert path %q", hostSslCert))
+ return nil, errors.Wrapf(err, "%s", tr.Tr.Get("Error resolving cert path %q", hostSslCert))
}
cert, err := os.ReadFile(hostSslCert)
if err != nil {
tracerx.Printf("Error reading client cert file %q: %v", hostSslCert, err)
- return nil, errors.Wrapf(err, tr.Tr.Get("Error reading client cert file %q", hostSslCert))
+ return nil, errors.Wrapf(err, "%s", tr.Tr.Get("Error reading client cert file %q", hostSslCert))
}
key, err := os.ReadFile(hostSslKey)
if err != nil {
tracerx.Printf("Error reading client key file %q: %v", hostSslKey, err)
- return nil, errors.Wrapf(err, tr.Tr.Get("Error reading client key file %q", hostSslKey))
+ return nil, errors.Wrapf(err, "%s", tr.Tr.Get("Error reading client key file %q", hostSslKey))
}
block, _ := pem.Decode(key)
@@ -103,14 +103,14 @@ func getClientCertForHost(c *Client, host string) (*tls.Certificate, error) {
key, err = decryptPEMBlock(c, block, hostSslKey, key)
if err != nil {
tracerx.Printf("Unable to decrypt client key file %q: %v", hostSslKey, err)
- return nil, errors.Wrapf(err, tr.Tr.Get("Error reading client key file %q (not a PKCS#1 file?)", hostSslKey))
+ return nil, errors.Wrapf(err, "%s", tr.Tr.Get("Error reading client key file %q (not a PKCS#1 file?)", hostSslKey))
}
}
certobj, err := tls.X509KeyPair(cert, key)
if err != nil {
tracerx.Printf("Error reading client cert/key %v", err)
- return nil, errors.Wrapf(err, tr.Tr.Get("Error reading client cert/key"))
+ return nil, errors.Wrapf(err, "%s", tr.Tr.Get("Error reading client cert/key"))
}
return &certobj, nil
}
diff --git a/lfshttp/errors.go b/lfshttp/errors.go
index 15340061..bc1e13d6 100644
--- a/lfshttp/errors.go
+++ b/lfshttp/errors.go
@@ -124,5 +124,10 @@ func defaultError(res *http.Response) error {
msgFmt = tr.Tr.Get("Server error %%s from HTTP %d", res.StatusCode)
}
- return errors.Errorf(fmt.Sprintf(msgFmt), res.Request.URL)
+ // Preserve exact original behavior but avoid format string warnings
+ // Original was: errors.Errorf(fmt.Sprintf(msgFmt), res.Request.URL)
+ // This is equivalent but avoids variable format strings
+ urlStr := fmt.Sprintf("%v", res.Request.URL) // Convert URL to string safely
+ finalMsg := strings.ReplaceAll(msgFmt, "%%s", urlStr) // Replace %%s with actual URL
+ return errors.New(finalMsg)
}
diff --git a/lfshttp/lfshttp.go b/lfshttp/lfshttp.go
index fa89714a..913442db 100644
--- a/lfshttp/lfshttp.go
+++ b/lfshttp/lfshttp.go
@@ -84,7 +84,7 @@ func DecodeJSON(res *http.Response, obj interface{}) error {
res.Body.Close()
if err != nil {
- return errors.Wrapf(err, tr.Tr.Get("Unable to parse HTTP response for %s %s", res.Request.Method, res.Request.URL))
+ return errors.Wrapf(err, "%s", tr.Tr.Get("Unable to parse HTTP response for %s %s", res.Request.Method, res.Request.URL))
}
return nil
diff --git a/lfshttp/standalone/standalone.go b/lfshttp/standalone/standalone.go
index 22a5902e..05b7a4b1 100644
--- a/lfshttp/standalone/standalone.go
+++ b/lfshttp/standalone/standalone.go
@@ -256,7 +256,7 @@ func (h *fileHandler) upload(oid string, size int64, path string) (string, strin
func (h *fileHandler) download(oid string, size int64) (string, string, error) {
if !h.remoteConfig.LFSObjectExists(oid, size) {
tracerx.Printf("missing object in %q (%s)", h.remotePath, oid)
- return oid, "", errors.Errorf(tr.Tr.Get("remote missing object %s", oid))
+ return oid, "", errors.Errorf("%s", tr.Tr.Get("remote missing object %s", oid))
}
src, err := h.remoteConfig.Filesystem().ObjectPath(oid)
@@ -290,13 +290,13 @@ func ProcessStandaloneData(cfg *config.Configuration, input *os.File, output *os
for scanner.Scan() {
var msg inputMessage
if err := json.NewDecoder(strings.NewReader(scanner.Text())).Decode(&msg); err != nil {
- return errors.Wrapf(err, tr.Tr.Get("error decoding JSON"))
+ return errors.Wrapf(err, "%s", tr.Tr.Get("error decoding JSON"))
}
if handler == nil {
var err error
handler, err = newHandler(cfg, output, &msg)
if err != nil {
- err := errors.Wrapf(err, tr.Tr.Get("error creating handler"))
+ err := errors.Wrapf(err, "%s", tr.Tr.Get("error creating handler"))
errMsg := outputErrorMessage{
Error: errorMessage{
Message: err.Error(),
@@ -314,7 +314,7 @@ func ProcessStandaloneData(cfg *config.Configuration, input *os.File, output *os
os.RemoveAll(handler.tempdir)
}
if err := scanner.Err(); err != nil {
- return errors.Wrapf(err, tr.Tr.Get("error reading input"))
+ return errors.Wrapf(err, "%s", tr.Tr.Get("error reading input"))
}
return nil
}
diff --git a/ssh/connection.go b/ssh/connection.go
index 83a4530c..f08165ae 100644
--- a/ssh/connection.go
+++ b/ssh/connection.go
@@ -80,7 +80,7 @@ func startConnection(id int, osEnv config.Environment, gitEnv config.Environment
r.Close()
w.Close()
cmd.Wait()
- err = errors.Combine([]error{err, fmt.Errorf(tr.Tr.Get("Failed to connect to remote SSH server: %s", cmd.Stderr))})
+ err = errors.Combine([]error{err, fmt.Errorf("%s", tr.Tr.Get("Failed to connect to remote SSH server: %s", cmd.Stderr))})
tracerx.Printf("pure SSH connection unsuccessful (#%d)", id)
} else {
tracerx.Printf("pure SSH connection successful (#%d)", id)
diff --git a/t/git-lfs-test-server-api/main.go b/t/git-lfs-test-server-api/main.go
index f897fd6e..6408fbdd 100644
--- a/t/git-lfs-test-server-api/main.go
+++ b/t/git-lfs-test-server-api/main.go
@@ -74,7 +74,7 @@ func testServerApi(cmd *cobra.Command, args []string) {
manifest, err := buildManifest(repo)
if err != nil {
- exit("error building tq.Manifest: " + err.Error())
+ exit("error building tq.Manifest: %s", err.Error())
}
var oidsExist, oidsMissing []TestObject
diff --git a/tasklog/simple_task.go b/tasklog/simple_task.go
index 207c5838..fb9c0988 100644
--- a/tasklog/simple_task.go
+++ b/tasklog/simple_task.go
@@ -28,7 +28,7 @@ func NewSimpleTask() *SimpleTask {
// Log logs a string with no formatting verbs.
func (s *SimpleTask) Log(str string) {
- s.Logf(str)
+ s.Logf("%s", str)
}
// Logf logs some formatted string, which is interpreted according to the rules
diff --git a/tools/filetools.go b/tools/filetools.go
index be97a800..05f56822 100644
--- a/tools/filetools.go
+++ b/tools/filetools.go
@@ -181,14 +181,14 @@ func ExpandPath(path string, expand bool) (string, error) {
}
if err != nil {
- return "", errors.Wrapf(err, tr.Tr.Get("could not find user %s", username))
+ return "", errors.Wrapf(err, "%s", tr.Tr.Get("could not find user %s", username))
}
homedir := who.HomeDir
if expand {
homedir, err = filepath.EvalSymlinks(homedir)
if err != nil {
- return "", errors.Wrapf(err, tr.Tr.Get("cannot eval symlinks for %s", homedir))
+ return "", errors.Wrapf(err, "%s", tr.Tr.Get("cannot eval symlinks for %s", homedir))
}
}
return filepath.Join(homedir, path[len(username)+1:]), nil
diff --git a/tq/basic_download.go b/tq/basic_download.go
index 767ebaee..c2aae578 100644
--- a/tq/basic_download.go
+++ b/tq/basic_download.go
@@ -118,7 +118,7 @@ func (a *basicDownloadAdapter) download(t *Transfer, cb ProgressCallback, authOk
return err
}
if rel == nil {
- return errors.Errorf(tr.Tr.Get("Object %s not found on the server.", t.Oid))
+ return errors.Errorf("%s", tr.Tr.Get("Object %s not found on the server.", t.Oid))
}
req, err := a.newHTTPRequest("GET", rel)
@@ -243,7 +243,7 @@ func (a *basicDownloadAdapter) download(t *Transfer, cb ProgressCallback, authOk
}
written, err := tools.CopyWithCallback(dlFile, hasher, res.ContentLength, ccb)
if err != nil {
- return errors.Wrapf(err, tr.Tr.Get("cannot write data to temporary file %q", dlfilename))
+ return errors.Wrapf(err, "%s", tr.Tr.Get("cannot write data to temporary file %q", dlfilename))
}
if actual := hasher.Hash(); actual != t.Oid {
diff --git a/tq/basic_upload.go b/tq/basic_upload.go
index 669a2015..b90278ad 100644
--- a/tq/basic_upload.go
+++ b/tq/basic_upload.go
@@ -47,7 +47,7 @@ func (a *basicUploadAdapter) DoTransfer(ctx interface{}, t *Transfer, cb Progres
return err
}
if rel == nil {
- return errors.Errorf(tr.Tr.Get("No upload action for object: %s", t.Oid))
+ return errors.Errorf("%s", tr.Tr.Get("No upload action for object: %s", t.Oid))
}
req, err := a.newHTTPRequest("PUT", rel)
@@ -142,7 +142,7 @@ func (a *basicUploadAdapter) DoTransfer(ctx interface{}, t *Transfer, cb Progres
}
if res.StatusCode > 299 {
- return errors.Wrapf(nil, tr.Tr.Get("Invalid status for %s %s: %d",
+ return errors.Wrapf(nil, "%s", tr.Tr.Get("Invalid status for %s %s: %d",
req.Method,
strings.SplitN(req.URL.String(), "?", 2)[0],
res.StatusCode,
diff --git a/tq/custom.go b/tq/custom.go
index 060e77db..f479d3d7 100644
--- a/tq/custom.go
+++ b/tq/custom.go
@@ -272,7 +272,7 @@ func (a *customAdapter) DoTransfer(ctx interface{}, t *Transfer, cb ProgressCall
return err
}
if rel == nil && !a.standalone {
- return errors.Errorf(tr.Tr.Get("Object %s not found on the server.", t.Oid))
+ return errors.Errorf("%s", tr.Tr.Get("Object %s not found on the server.", t.Oid))
}
var req *customAdapterTransferRequest
if a.direction == Upload {
diff --git a/tq/ssh.go b/tq/ssh.go
index 79693495..235644ef 100644
--- a/tq/ssh.go
+++ b/tq/ssh.go
@@ -194,7 +194,7 @@ func (a *SSHAdapter) download(t *Transfer, workerNum int, cb ProgressCallback) e
return err
}
if rel == nil {
- return errors.Errorf(tr.Tr.Get("No download action for object: %s", t.Oid))
+ return errors.Errorf("%s", tr.Tr.Get("No download action for object: %s", t.Oid))
}
// Reserve a temporary filename. We need to make sure nobody operates on the file simultaneously with us.
f, err := tools.TempFile(a.tempDir(), t.Oid, a.fs)
@@ -267,7 +267,7 @@ func (a *SSHAdapter) doDownload(t *Transfer, workerNum int, f *os.File, cb Progr
hasher := tools.NewHashingReader(data)
written, err := tools.CopyWithCallback(f, hasher, t.Size, ccb)
if err != nil {
- return errors.Wrapf(err, tr.Tr.Get("cannot write data to temporary file %q", dlfilename))
+ return errors.Wrapf(err, "%s", tr.Tr.Get("cannot write data to temporary file %q", dlfilename))
}
if actual := hasher.Hash(); actual != t.Oid {
@@ -346,7 +346,7 @@ func (a *SSHAdapter) upload(t *Transfer, workerNum int, cb ProgressCallback) err
return err
}
if rel == nil {
- return errors.Errorf(tr.Tr.Get("No upload action for object: %s", t.Oid))
+ return errors.Errorf("%s", tr.Tr.Get("No upload action for object: %s", t.Oid))
}
f, err := os.OpenFile(t.Path, os.O_RDONLY, 0644)
diff --git a/tq/transfer_queue.go b/tq/transfer_queue.go
index ad779d34..26effe13 100644
--- a/tq/transfer_queue.go
+++ b/tq/transfer_queue.go
@@ -648,7 +648,7 @@ func (q *TransferQueue) enqueueAndCollectRetriesFor(batch batch) (batch, error)
// Transfer object, then we give up on the
// transfer by telling the progress meter to
// skip the number of bytes in "o".
- q.errorc <- errors.Errorf(tr.Tr.Get("[%v] The server returned an unknown OID.", o.Oid))
+ q.errorc <- errors.Errorf("%s", tr.Tr.Get("[%v] The server returned an unknown OID.", o.Oid))
q.Skip(o.Size)
q.wait.Done()
@@ -748,7 +748,7 @@ func (q *TransferQueue) partitionTransfers(transfers []*Transfer) (present []*Tr
var err error
if t.Size < 0 {
- err = errors.Errorf(tr.Tr.Get("object %q has invalid size (got: %d)", t.Oid, t.Size))
+ err = errors.Errorf("%s", tr.Tr.Get("object %q has invalid size (got: %d)", t.Oid, t.Size))
} else {
fd, serr := os.Stat(t.Path)
if serr != nil {
diff --git a/tq/tus_upload.go b/tq/tus_upload.go
index 273cb7fc..27f47542 100644
--- a/tq/tus_upload.go
+++ b/tq/tus_upload.go
@@ -34,7 +34,7 @@ func (a *tusUploadAdapter) DoTransfer(ctx interface{}, t *Transfer, cb ProgressC
return err
}
if rel == nil {
- return errors.Errorf(tr.Tr.Get("No upload action for object: %s", t.Oid))
+ return errors.Errorf("%s", tr.Tr.Get("No upload action for object: %s", t.Oid))
}
// Note not supporting the Creation extension since the batch API generates URLs
@@ -142,7 +142,7 @@ func (a *tusUploadAdapter) DoTransfer(ctx interface{}, t *Transfer, cb ProgressC
}
if res.StatusCode > 299 {
- return errors.Wrapf(nil, tr.Tr.Get("Invalid status for %s %s: %d",
+ return errors.Wrapf(nil, "%s", tr.Tr.Get("Invalid status for %s %s: %d",
req.Method,
strings.SplitN(req.URL.String(), "?", 2)[0],
res.StatusCode,
--
2.50.1

View File

@ -0,0 +1,25 @@
From a119ca768dfeefef7609b55acbf6400fafb0ee5a Mon Sep 17 00:00:00 2001
From: "brian m. carlson" <bk2204@github.com>
Date: Mon, 25 Jul 2022 17:29:34 +0000
Subject: [PATCH] t: set init.defaultBranch
Previously, we used a template to set the default HEAD ref to "main" so
that our branch would be correct. It appears that Git has changed
things so that that no longer works, so set init.defaultBranch as well
to make sure we initialize new repositories properly.
---
t/testhelpers.sh | 1 +
1 file changed, 1 insertion(+)
diff --git a/t/testhelpers.sh b/t/testhelpers.sh
index 7c921f43e8..ea5dc05c4f 100644
--- a/t/testhelpers.sh
+++ b/t/testhelpers.sh
@@ -607,6 +607,7 @@ setup() {
git config --global http.$LFS_CLIENT_CERT_URL/.sslKey "$LFS_CLIENT_KEY_FILE"
git config --global http.$LFS_CLIENT_CERT_URL/.sslCert "$LFS_CLIENT_CERT_FILE"
git config --global http.$LFS_CLIENT_CERT_URL/.sslVerify "false"
+ git config --global init.defaultBranch main
fi | sed -e 's/^/# /g'
# setup the git credential password storage

11
README.Fedora Normal file
View File

@ -0,0 +1,11 @@
git-lfs on Fedora
=================
By default, the package will run a post-install/post-uninstall task to
enable/disable git-lfs filters in the system git configuration.
If you wish to enable/disable git-lfs manually, you can set the following
option in the system git config, and package install/uninstall will no longer
do this:
# git config --system 'fedora.git-lfs.no-modify-config' true

View File

@ -1,15 +0,0 @@
# As `asciidoctor` package has not been packaged to RHEL 8:
# Pass package version(eg. `3.4.0`) as argument
VERSION=$1
cd git-lfs-$VERSION
make man GIT_LFS_SHA=unused VERSION=unused PREFIX=unused
rm -r man/html
tar -czvf manpages.tgz man/*
cp manpages.tgz ../

View File

@ -1,358 +0,0 @@
diff -urN b/creds/creds.go a/creds/creds.go
--- b/creds/creds.go 2023-12-13 19:56:25.000000000 +0100
+++ a/creds/creds.go 2025-01-17 08:55:10.175959181 +0100
@@ -53,11 +53,20 @@
// as input.
type Creds map[string][]string
-func bufferCreds(c Creds) *bytes.Buffer {
+func (c Creds) buffer(protectProtocol bool) (*bytes.Buffer, error) {
buf := new(bytes.Buffer)
for k, v := range c {
for _, item := range v {
+ if strings.Contains(item, "\n") {
+ return nil, errors.Errorf(tr.Tr.Get("credential value for %s contains newline: %q", k, item))
+ }
+ if protectProtocol && strings.Contains(item, "\r") {
+ return nil, errors.Errorf(tr.Tr.Get("credential value for %s contains carriage return: %q\nIf this is intended, set `credential.protectProtocol=false`", k, item))
+ }
+ if strings.Contains(item, string(rune(0))) {
+ return nil, errors.Errorf(tr.Tr.Get("credential value for %s contains null byte: %q", k, item))
+ }
buf.Write([]byte(k))
buf.Write([]byte("="))
buf.Write([]byte(item))
@@ -65,7 +74,7 @@
}
}
- return buf
+ return buf, nil
}
type CredentialHelperContext struct {
@@ -153,6 +162,9 @@
helpers = append(helpers, ctxt.askpassCredHelper)
}
}
+
+ ctxt.commandCredHelper.protectProtocol = ctxt.urlConfig.Bool("credential", rawurl, "protectProtocol", true)
+
return CredentialHelperWrapper{CredentialHelper: NewCredentialHelpers(append(helpers, ctxt.commandCredHelper)), Input: input, Url: u}
}
@@ -292,7 +304,8 @@
}
type commandCredentialHelper struct {
- SkipPrompt bool
+ SkipPrompt bool
+ protectProtocol bool
}
func (h *commandCredentialHelper) Fill(creds Creds) (Creds, error) {
@@ -323,7 +336,10 @@
if err != nil {
return nil, errors.New(tr.Tr.Get("failed to find `git credential %s`: %v", subcommand, err))
}
- cmd.Stdin = bufferCreds(input)
+ cmd.Stdin, err = input.buffer(h.protectProtocol)
+ if err != nil {
+ return nil, errors.New(tr.Tr.Get("invalid input to `git credential %s`: %v", subcommand, err))
+ }
cmd.Stdout = output
/*
There is a reason we don't read from stderr here:
diff -urN b/creds/creds_test.go a/creds/creds_test.go
--- b/creds/creds_test.go 2023-12-13 19:56:25.000000000 +0100
+++ a/creds/creds_test.go 2025-01-17 08:55:21.318023782 +0100
@@ -1,12 +1,89 @@
package creds
import (
+ "bytes"
"errors"
+ "slices"
+ "strings"
"testing"
"github.com/stretchr/testify/assert"
)
+func assertCredsLinesMatch(t *testing.T, expected []string, buf *bytes.Buffer) {
+ actual := strings.SplitAfter(buf.String(), "\n")
+
+ slices.Sort(expected)
+ slices.Sort(actual)
+
+ assert.Equal(t, expected, actual)
+}
+func TestCredsBufferFormat(t *testing.T) {
+ creds := make(Creds)
+
+ expected := []string{""}
+
+ buf, err := creds.buffer(true)
+ assert.NoError(t, err)
+ assertCredsLinesMatch(t, expected, buf)
+
+ creds["protocol"] = []string{"https"}
+ creds["host"] = []string{"example.com"}
+
+ expected = []string{"host=example.com\n", "protocol=https\n", ""}
+
+ buf, err = creds.buffer(true)
+ assert.NoError(t, err)
+ assertCredsLinesMatch(t, expected, buf)
+
+ creds["wwwauth[]"] = []string{"Basic realm=test", "Negotiate"}
+
+ expected = append(expected, "wwwauth[]=Basic realm=test\n", "wwwauth[]=Negotiate\n")
+ buf, err = creds.buffer(true)
+ assert.NoError(t, err)
+ assertCredsLinesMatch(t, expected, buf)
+}
+
+func TestCredsBufferProtect(t *testing.T) {
+ creds := make(Creds)
+
+ // Always disallow LF characters
+ creds["protocol"] = []string{"https"}
+ creds["host"] = []string{"one.example.com\nhost=two.example.com"}
+
+ buf, err := creds.buffer(false)
+ assert.Error(t, err)
+ assert.Nil(t, buf)
+
+ buf, err = creds.buffer(true)
+ assert.Error(t, err)
+ assert.Nil(t, buf)
+
+ // Disallow CR characters unless protocol protection disabled
+ creds["host"] = []string{"one.example.com\rhost=two.example.com"}
+
+ expected := []string{"", "protocol=https\n", "host=one.example.com\rhost=two.example.com\n"}
+
+ buf, err = creds.buffer(false)
+ assert.NoError(t, err)
+ assertCredsLinesMatch(t, expected, buf)
+
+ buf, err = creds.buffer(true)
+ assert.Error(t, err)
+ assert.Nil(t, buf)
+
+ // Always disallow null bytes
+ creds["host"] = []string{"one.example.com\x00host=two.example.com"}
+
+ buf, err = creds.buffer(false)
+ assert.Error(t, err)
+ assert.Nil(t, buf)
+
+ buf, err = creds.buffer(true)
+ assert.Error(t, err)
+ assert.Nil(t, buf)
+}
+
type testCredHelper struct {
fillErr error
approveErr error
diff -urN b/t/cmd/lfstest-gitserver.go a/t/cmd/lfstest-gitserver.go
--- b/t/cmd/lfstest-gitserver.go 2023-12-13 19:56:25.000000000 +0100
+++ a/t/cmd/lfstest-gitserver.go 2025-01-16 14:33:23.825991696 +0100
@@ -27,6 +27,7 @@
"net/http"
"net/http/httptest"
"net/textproto"
+ "net/url"
"os"
"os/exec"
"regexp"
@@ -252,6 +253,7 @@
}
func lfsUrl(repo, oid string, redirect bool) string {
+ repo = url.QueryEscape(repo)
if redirect {
return server.URL + "/redirect307/objects/" + oid + "?r=" + repo
}
diff -urN b/t/t-credentials-protect.sh a/t/t-credentials-protect.sh
--- b/t/t-credentials-protect.sh 1970-01-01 01:00:00.000000000 +0100
+++ a/t/t-credentials-protect.sh 2025-01-16 14:03:23.597029590 +0100
@@ -0,0 +1,146 @@
+#!/usr/bin/env bash
+
+. "$(dirname "$0")/testlib.sh"
+
+ensure_git_version_isnt $VERSION_LOWER "2.3.0"
+
+export CREDSDIR="$REMOTEDIR/creds-credentials-protect"
+setup_creds
+
+# Copy the default record file for the test credential helper to match the
+# hostname used in the Git LFS configurations of the tests.
+cp "$CREDSDIR/127.0.0.1" "$CREDSDIR/localhost"
+
+begin_test "credentials rejected with line feed"
+(
+ set -e
+
+ reponame="protect-linefeed"
+ setup_remote_repo "$reponame"
+ clone_repo "$reponame" "$reponame"
+
+ contents="a"
+ contents_oid=$(calc_oid "$contents")
+
+ git lfs track "*.dat"
+ printf "%s" "$contents" >a.dat
+ git add .gitattributes a.dat
+ git commit -m "add a.dat"
+
+ # Using localhost instead of 127.0.0.1 in the LFS API URL ensures this URL
+ # is used when filling credentials rather than the Git remote URL, which
+ # would otherwise be used since it would have the same scheme and hostname.
+ gitserver="$(echo "$GITSERVER" | sed 's/127\.0\.0\.1/localhost/')"
+ testreponame="test%0a$reponame"
+ git config lfs.url "$gitserver/$testreponame.git/info/lfs"
+
+ GIT_TRACE=1 git lfs push origin main 2>&1 | tee push.log
+ if [ "0" -eq "${PIPESTATUS[0]}" ]; then
+ echo >&2 "fatal: expected 'git lfs push' to fail ..."
+ exit 1
+ fi
+ grep "batch response: Git credentials for $gitserver.* not found" push.log
+ grep "credential value for path contains newline" push.log
+ refute_server_object "$testreponame" "$contents_oid"
+
+ git config credential.protectProtocol false
+
+ GIT_TRACE=1 git lfs push origin main 2>&1 | tee push.log
+ if [ "0" -eq "${PIPESTATUS[0]}" ]; then
+ echo >&2 "fatal: expected 'git lfs push' to fail ..."
+ exit 1
+ fi
+ grep "batch response: Git credentials for $gitserver.* not found" push.log
+ grep "credential value for path contains newline" push.log
+ refute_server_object "$testreponame" "$contents_oid"
+)
+end_test
+
+begin_test "credentials rejected with carriage return"
+(
+ set -e
+
+ reponame="protect-return"
+ setup_remote_repo "$reponame"
+ clone_repo "$reponame" "$reponame"
+
+ contents="a"
+ contents_oid=$(calc_oid "$contents")
+
+ git lfs track "*.dat"
+ printf "%s" "$contents" >a.dat
+ git add .gitattributes a.dat
+ git commit -m "add a.dat"
+
+ # Using localhost instead of 127.0.0.1 in the LFS API URL ensures this URL
+ # is used when filling credentials rather than the Git remote URL, which
+ # would otherwise be used since it would have the same scheme and hostname.
+ gitserver="$(echo "$GITSERVER" | sed 's/127\.0\.0\.1/localhost/')"
+ testreponame="test%0d$reponame"
+ git config lfs.url "$gitserver/$testreponame.git/info/lfs"
+
+ GIT_TRACE=1 git lfs push origin main 2>&1 | tee push.log
+ if [ "0" -eq "${PIPESTATUS[0]}" ]; then
+ echo >&2 "fatal: expected 'git lfs push' to fail ..."
+ exit 1
+ fi
+ grep "batch response: Git credentials for $gitserver.* not found" push.log
+ grep "credential value for path contains carriage return" push.log
+ refute_server_object "$testreponame" "$contents_oid"
+
+ git config credential.protectProtocol false
+
+ git lfs push origin main 2>&1 | tee push.log
+ if [ "0" -ne "${PIPESTATUS[0]}" ]; then
+ echo >&2 "fatal: expected 'git lfs push' to succeed ..."
+ exit 1
+ fi
+ [ $(grep -c "Uploading LFS objects: 100% (1/1)" push.log) -eq 1 ]
+ assert_server_object "$testreponame" "$contents_oid"
+)
+end_test
+
+begin_test "credentials rejected with null byte"
+(
+ set -e
+
+ reponame="protect-null"
+ setup_remote_repo "$reponame"
+ clone_repo "$reponame" "$reponame"
+
+ contents="a"
+ contents_oid=$(calc_oid "$contents")
+
+ git lfs track "*.dat"
+ printf "%s" "$contents" >a.dat
+ git add .gitattributes a.dat
+ git commit -m "add a.dat"
+
+ # Using localhost instead of 127.0.0.1 in the LFS API URL ensures this URL
+ # is used when filling credentials rather than the Git remote URL, which
+ # would otherwise be used since it would have the same scheme and hostname.
+ gitserver="$(echo "$GITSERVER" | sed 's/127\.0\.0\.1/localhost/')"
+ testreponame="test%00$reponame"
+ git config lfs.url "$gitserver/$testreponame.git/info/lfs"
+
+ GIT_TRACE=1 git lfs push origin main 2>&1 | tee push.log
+ if [ "0" -eq "${PIPESTATUS[0]}" ]; then
+ echo >&2 "fatal: expected 'git lfs push' to fail ..."
+ exit 1
+ fi
+ grep "batch response: Git credentials for $gitserver.* not found" push.log
+ grep "credential value for path contains null byte" push.log
+ refute_server_object "$testreponame" "$contents_oid"
+
+ git config credential.protectProtocol false
+
+ GIT_TRACE=1 git lfs push origin main 2>&1 | tee push.log
+ if [ "0" -eq "${PIPESTATUS[0]}" ]; then
+ echo >&2 "fatal: expected 'git lfs push' to fail ..."
+ exit 1
+ fi
+ grep "batch response: Git credentials for $gitserver.* not found" push.log
+ grep "credential value for path contains null byte" push.log
+ refute_server_object "$testreponame" "$contents_oid"
+)
+end_test
diff -urN b/t/testhelpers.sh a/t/testhelpers.sh
--- b/t/testhelpers.sh 2023-12-13 19:56:25.000000000 +0100
+++ a/t/testhelpers.sh 2025-01-16 14:15:19.240279305 +0100
@@ -557,6 +557,14 @@
fi
}
+
+setup_creds() {
+ mkdir -p "$CREDSDIR"
+ write_creds_file "user:pass" "$CREDSDIR/127.0.0.1"
+ write_creds_file ":pass" "$CREDSDIR/--$certpath"
+ write_creds_file ":pass" "$CREDSDIR/--$keypath"
+}
+
# setup initializes the clean, isolated environment for integration tests.
setup() {
cd "$ROOTDIR"
@@ -613,10 +621,7 @@
# setup the git credential password storage
local certpath="$(echo "$LFS_CLIENT_CERT_FILE" | tr / -)"
local keypath="$(echo "$LFS_CLIENT_KEY_FILE_ENCRYPTED" | tr / -)"
- mkdir -p "$CREDSDIR"
- write_creds_file "user:pass" "$CREDSDIR/127.0.0.1"
- write_creds_file ":pass" "$CREDSDIR/--$certpath"
- write_creds_file ":pass" "$CREDSDIR/--$keypath"
+ setup_creds
echo "#"
echo "# HOME: $HOME"

6
gating.yaml Normal file
View File

@ -0,0 +1,6 @@
--- !Policy
product_versions:
- rhel-9
decision_context: osci_compose_gate
rules:
- !PassingTestCaseRule {test_case_name: baseos-ci.brew-build.tier1.functional}

View File

@ -1,39 +1,26 @@
# Build man pages
%global with_manpages 1
%bcond_without check
# https://github.com/git-lfs/git-lfs
%global goipath github.com/git-lfs/git-lfs
Version: 3.4.1
%global goipath github.com/git-lfs/git-lfs/v3
Version: 3.6.1
# golang doesn't ship i686 binaries, we don't need the build
# https://bugzilla.redhat.com/show_bug.cgi?id=1752991#c9
%global golang_arches %(echo %{golang_arches} | sed "s|%{ix86}||")
%gometa
%global gobuilddir %{_builddir}/%{name}-%{version}/_build
# define gobuild macro to not lose hardening, because of macro conflict
# https://bugzilla.redhat.com/show_bug.cgi?id=1919348
%global gobuild CGO_CPPFLAGS="-D_FORTIFY_SOURCE=2 -fstack-protector-all" go build -compiler gc -buildmode pie '-tags=rpm_crashtraceback libtrust_openssl ' -ldflags "-linkmode=external -compressdwarf=false ${LDFLAGS:-} -B 0x$(head -c20 /dev/urandom|od -An -tx1|tr -d ' \\n') -extldflags '%__global_ldflags'" -a -v -x %{?**}
Name: git-lfs
Release: 5%{?dist}
Release: 3%{?dist}
Summary: Git extension for versioning large files
License: MIT
URL: https://git-lfs.github.io/
Source0: https://github.com/%{name}/%{name}/releases/download/v%{version}/%{name}-v%{version}.tar.gz
Source1: manpages.tgz
# See this script. Generating of manpages is performed on other distros due to some missing rubygem-asciidoctor on RHEL-8
Source2: gen-manpages.sh
Source1: README.Fedora
# https://github.com/advisories/GHSA-q6r2-x2cc-vrp7
# Backports 268628b, 4423696, 0345b6f and f6904cc that resolves the CVE-2024-53263
# Aditionally backports b326b63
# Commits had to be adapted as git-lfs-3.4.1 doesn't support multistage authentication
Patch: git-lfs-3.4.1-cve-2024-53263.patch
# Without this patch, Git-LFS fails to build with Go 1.24<
# Based on https://github.com/git-lfs/git-lfs/pull/5998
# Added logic that preserves original behavior of error messages and avoids the format string test failures
Patch0: 0001-Use-constant-format-string.patch
# Generated provides by vendor2provides.py
# https://src.fedoraproject.org/rpms/syncthing/blob/603e4e03a92a7d704d199629dd85304018e8279d/f/vendor2provides.py
@ -46,36 +33,40 @@ Provides: bundled(golang(github.com/git-lfs/go-netrc)) = f0c862d
Provides: bundled(golang(github.com/git-lfs/pktline)) = 06e9096
Provides: bundled(golang(github.com/git-lfs/wildmatch/v2)) = 2.0.1
Provides: bundled(golang(github.com/hashicorp/go-uuid)) = 1.0.2
Provides: bundled(golang(github.com/inconshreveable/mousetrap)) = 1.0.1
Provides: bundled(golang(github.com/inconshreveable/mousetrap)) = 1.1.0
Provides: bundled(golang(github.com/jcmturner/aescts/v2)) = 2.0.0
Provides: bundled(golang(github.com/jcmturner/dnsutils/v2)) = 2.0.0
Provides: bundled(golang(github.com/jcmturner/gofork)) = 1.0.0
Provides: bundled(golang(github.com/jcmturner/goidentity/v6)) = 6.0.1
Provides: bundled(golang(github.com/jcmturner/gokrb5/v8)) = 8.4.2
Provides: bundled(golang(github.com/jcmturner/rpc/v2)) = 2.0.3
Provides: bundled(golang(github.com/jmhodges/clock)) = 1.2.0
Provides: bundled(golang(github.com/leonelquinteros/gotext)) = 1.5.0
Provides: bundled(golang(github.com/mattn/go-isatty)) = 0.0.4
Provides: bundled(golang(github.com/olekukonko/ts)) = 78ecb04
Provides: bundled(golang(github.com/pkg/errors)) = c605e28
Provides: bundled(golang(github.com/pmezard/go-difflib)) = 1.0.0
Provides: bundled(golang(github.com/rubyist/tracerx)) = 7879593
Provides: bundled(golang(github.com/spf13/cobra)) = 1.6.0
Provides: bundled(golang(github.com/spf13/cobra)) = 1.7.0
Provides: bundled(golang(github.com/spf13/pflag)) = 1.0.5
Provides: bundled(golang(github.com/ssgelm/cookiejarparser)) = 1.0.1
Provides: bundled(golang(github.com/stretchr/testify)) = 1.6.1
Provides: bundled(golang(github.com/xeipuuv/gojsonpointer)) = 4e3ac27
Provides: bundled(golang(github.com/xeipuuv/gojsonreference)) = bd5ef7b
Provides: bundled(golang(github.com/xeipuuv/gojsonschema)) = 6b67b3f
Provides: bundled(golang(golang.org/x/crypto)) = 7b82a4e
Provides: bundled(golang(golang.org/x/net)) = 0.7.0
Provides: bundled(golang(golang.org/x/crypto)) = 0.21.0
Provides: bundled(golang(golang.org/x/net)) = 0.23.0
Provides: bundled(golang(golang.org/x/sync)) = 0.1.0
Provides: bundled(golang(golang.org/x/sys)) = 0.5.0
Provides: bundled(golang(golang.org/x/text)) = 0.7.0
Provides: bundled(golang(golang.org/x/sys)) = 0.18.0
Provides: bundled(golang(golang.org/x/text)) = 0.14.0
Provides: bundled(golang(gopkg.in/yaml.v3)) = 3.0.1
%if 0%{?with_check}
# For tests
# Generate man pages
BuildRequires: /usr/bin/asciidoctor
%if %{with check}
# Tests
BuildRequires: perl-Digest-SHA
BuildRequires: perl-Test-Harness
# Tests require full git suite, but not generally needed.
@ -97,11 +88,6 @@ install -m 0755 -vd %{gobuilddir}/bin
install -m 0755 -vd "$(dirname %{gobuilddir}/src/%{goipath})"
ln -fs "$(pwd)" "%{gobuilddir}/src/%{goipath}"
%if %{?with_manpages}
# Unpack manpages generated by %%{SOURCE2}
tar -xf %{SOURCE1}
%endif
# Modify tests so that they expect binaries where we build them.
sed -i -e 's!\.\./bin/!/%{gobuilddir}/bin/!g' t/Makefile
sed -i -e 's!^BINPATH=.\+!BINPATH="%{gobuilddir}/bin"!g' t/testenv.sh
@ -110,13 +96,15 @@ sed -i -e 's!^BINPATH=.\+!BINPATH="%{gobuilddir}/bin"!g' t/testenv.sh
export GOPATH=%{gobuilddir}:%{gopath}
export GO111MODULE=off
# Enable FIPS support at build time by enabling CGO and enforcing strict FIPS runtime
export CGO_ENABLED=1
export GOEXPERIMENT=strictfipsruntime
# Build manpages first (some embedding in the executable is done.)
make man GIT_LFS_SHA=unused VERSION=unused PREFIX=unused
pushd docs
%gobuild -o mangen man/mangen.go
./mangen
# Removes unwanted source files
# https://bugzilla.redhat.com/show_bug.cgi?id=1852842
rm mangen man/mangen.go
%gobuild -o %{gobuilddir}/bin/mangen man/mangen.go
%{gobuilddir}/bin/mangen
popd
%gobuild -o %{gobuilddir}/bin/git-lfs %{goipath}
@ -129,21 +117,17 @@ done
%gobuild -o "%{gobuilddir}/bin/git-lfs-test-server-api" t/git-lfs-test-server-api/*.go
popd
# Remove man pages from docs so they don't get installed twice.
rm -r docs/man
%install
# In Fedora this is done by using %%gopkginstall
install -Dpm0755 %{gobuilddir}/bin/git-lfs %{buildroot}%{_bindir}/%{name}
install -d -p %{buildroot}%{_mandir}/man1/
install -Dpm0644 man/man1/*.1 %{buildroot}%{_mandir}/man1/
install -d -p %{buildroot}%{_mandir}/man5/
install -Dpm0644 man/man5/*.5 %{buildroot}%{_mandir}/man5/
install -d -p %{buildroot}%{_mandir}/man7/
install -Dpm0644 man/man7/*.7 %{buildroot}%{_mandir}/man7/
# Remove unwanted files from man folder
# https://bugzilla.redhat.com/show_bug.cgi?id=1852842
rm -r man/*
for section in 1 5 7; do
install -d -p %{buildroot}%{_mandir}/man${section}/
install -Dpm0644 man/man${section}/*.${section} %{buildroot}%{_mandir}/man${section}/
done
%post
%{_bindir}/%{name} install --system --skip-repo
@ -157,6 +141,7 @@ exit 0
%if %{with check}
%check
%gocheck
PATH=%{buildroot}%{_bindir}:%{gobuilddir}/bin:$PATH \
# https://github.com/git-lfs/git-lfs/issues/5609
# tests fails when running with low level of parallelism
@ -175,58 +160,144 @@ PATH=%{buildroot}%{_bindir}:%{gobuilddir}/bin:$PATH \
%changelog
* Tue Jun 10 2025 Ondřej Pohořelský <opohorel@redhat.com> - 3.4.1-5
* Mon Aug 11 2025 Ondřej Pohořelský <opohorel@redhat.com> - 3.6.1-3
- Add patch to fix build failures with Go 1.24<
- Resolves: RHEL-106475
* Tue Jun 03 2025 Ondřej Pohořelský <opohorel@redhat.com> - 3.6.1-2
- Rebuild with new Golang
- Resolves: RHEL-89264
- Resolves: RHEL-89304
* Fri Jan 17 2025 Ondřej Pohořelský <opohorel@redhat.com> - 3.4.1-4
- Backport CVE-2024-53263 fixes
- Resolves: RHEL-73931
* Wed Jan 15 2025 Ondřej Pohořelský <opohorel@redhat.com> - 3.6.1-1
- Update to 3.6.1
- Resolves: RHEL-73940
* Mon Sep 23 2024 Ondřej Pohořelský <opohorel@redhat.com> - 3.4.1-3
* Thu Nov 28 2024 Ondřej Pohořelský <opohorel@redhat.com> - 3.6.0-1
- Update to 3.6.0
- Resolves: RHEL-63968, RHEL-61045, RHEL-47219, RHEL-43318, RHEL-35936, RHEL-2791
* Wed Aug 07 2024 Ondřej Pohořelský <opohorel@redhat.com> - 3.4.1-3
- Make Git-LFS FIPS compliant
- Resolves: RHEL-53086
* Wed May 22 2024 Ondřej Pohořelský <opohorel@redhat.com> - 3.4.1-2
- Rebuild with new Golang
- Resolves: RHEL-57900
- Resolves: RHEL-32571
* Mon Apr 22 2024 Ondřej Pohořelský <opohorel@redhat.com> - 3.4.1-2
- Rebuild with new Golang
- Resolves: RHEL-32543, RHEL-28377, RHEL-28399, RHEL-28423
* Mon Dec 18 2023 Ondřej Pohořelský <opohorel@redhat.com> - 3.4.1-1
- Update to 3.4.1
- Resolves: RHEL-17101
* Mon Dec 18 2023 Ondrej Pohorelsky <opohorel@redhat.com> - 3.4.1-1
- Update to version 3.4.1
- Resolves: RHEL-17102
* Thu Jan 05 2023 Ondřej Pohořelský <opohorel@redhat.com> - 3.2.0-1
- Update to 3.2.0
- Resolves: #2139383
* Mon Jan 30 2023 Ondrej Pohorelsky <opohorel@redhat.com> - 3.2.0-2
- Rebuild with Golang-1.19.4
- Resolves: #2163744
* Mon Aug 09 2021 Mohan Boddu <mboddu@redhat.com> - 2.13.3-4
- Rebuilt for IMA sigs, glibc 2.34, aarch64 flags
Related: rhbz#1991688
* Mon Jan 09 2023 Ondrej Pohorelsky <opohorel@redhat.com> - 3.2.0-1
- Update to version 3.2.0
- Resolves: #2139382
* Tue Jun 22 2021 Mohan Boddu <mboddu@redhat.com> - 2.13.3-3
- Rebuilt for RHEL 9 BETA for openssl 3.0
Related: rhbz#1971065
* Mon Jan 17 2022 Ondrej Pohorelsky <opohorel@redhat.com> - 2.13.3-2
- Define %%gobuild macro with proper ldflags
- Related: rhbz#2021549
* Wed May 05 2021 Ondřej Pohořelský <opohorel@redhat.com> - 2.13.3-2
- Fixed name of source tarball
- Fixed date in the latest changelog entry
- Related: #1952517
* Tue Nov 23 2021 Ondrej Pohorelsky <opohorel@redhat.com> - 2.13.3-1
- Update to version 2.13.3
- Fixed round brackets in Provides
- Moved manpages.tgz to look-a-side cache
- Resolves: rhbz#2021549, rhbz#1870080, rhbz#1866441
* Thu Apr 22 2021 Ondřej Pohořelský <opohorel@redhat.com> - 2.13.3-1
- Update to latest version
- Resolves: #1952517
* Wed Jul 1 2020 Ondrej Pohorelsky <opohorel@redhat.com> - 2.11.0-2
- Removed mangen source file
- Cleaned docs/man folder
- Resolves: rhbz#1852842
* Thu Apr 15 2021 Mohan Boddu <mboddu@redhat.com> - 2.13.0-2
- Rebuilt for RHEL 9 BETA on Apr 15th 2021. Related: rhbz#1947937
* Wed Jun 10 2020 Ondrej Pohorelsky <opohorel@redhat.com> - 2.11.0-1
- Update to version 2.11.0
- Resolves: rhbz#1783391
* Wed Jan 06 2021 Ondřej Pohořelský <opohorel@redhat.com> - 2.13.0-1
- Enable bundling
- Update to latest version
* Thu Jul 19 2018 Sebastian Kisela <skisela@redhat.com> - 2.4.1-3
- Add pregenerated manpages, due to missing dependency 'ronn' in rhel7.
* Mon Nov 09 2020 Elliott Sales de Andrade <quantum.analyst@gmail.com> - 2.12.1-1
- Update to latest version (#1894780)
* Wed Jul 18 2018 Sebastian Kisela <skisela@redhat.com> - 2.4.1-2
- Initial build for rh-git218-git-lfs-2.4.1
* Thu Sep 03 2020 Elliott Sales de Andrade <quantum.analyst@gmail.com> - 2.12.0-1
- Update to latest version (#1874604)
- Remove duplicate docs/man directory (#1852765)
- Add an option to disable modifying the git filter config (#1768060)
* Sat Aug 01 2020 Fedora Release Engineering <releng@fedoraproject.org> - 2.11.0-3
- Second attempt - Rebuilt for
https://fedoraproject.org/wiki/Fedora_33_Mass_Rebuild
* Mon Jul 27 2020 Fedora Release Engineering <releng@fedoraproject.org> - 2.11.0-2
- Rebuilt for https://fedoraproject.org/wiki/Fedora_33_Mass_Rebuild
* Sun May 10 2020 Elliott Sales de Andrade <quantum.analyst@gmail.com> - 2.11.0-1
- Update to latest version
* Thu Feb 20 2020 Elliott Sales de Andrade <quantum.analyst@gmail.com> - 2.10.0-1
- Update to latest version
* Tue Jan 28 2020 Fedora Release Engineering <releng@fedoraproject.org> - 2.9.2-2
- Rebuilt for https://fedoraproject.org/wiki/Fedora_32_Mass_Rebuild
* Tue Jan 07 2020 Elliott Sales de Andrade <quantum.analyst@gmail.com> - 2.9.2-1
- Update to latest version
* Wed Jan 01 2020 Elliott Sales de Andrade <quantum.analyst@gmail.com> - 2.9.0-1
- Update to latest version
* Fri Aug 30 2019 Elliott Sales de Andrade <quantum.analyst@gmail.com> - 2.8.0-4
- Customize vendor information in version
* Fri Aug 30 2019 Elliott Sales de Andrade <quantum.analyst@gmail.com> - 2.8.0-3
- Update to latest version
* Thu Jul 25 2019 Fedora Release Engineering <releng@fedoraproject.org> - 2.7.2-3
- Rebuilt for https://fedoraproject.org/wiki/Fedora_31_Mass_Rebuild
* Wed Jul 10 2019 Elliott Sales de Andrade <quantum.analyst@gmail.com> - 2.7.2-2
- Update to latest Go macros
* Wed Apr 24 2019 Elliott Sales de Andrade <quantum.analyst@gmail.com> - 2.7.2-1
- Update to latest version
* Wed Feb 27 2019 Elliott Sales de Andrade <quantum.analyst@gmail.com> - 2.7.1-1
- Update to latest version
* Thu Feb 21 2019 Elliott Sales de Andrade <quantum.analyst@gmail.com> - 2.7.0-1
- Update to latest version
* Thu Jan 31 2019 Fedora Release Engineering <releng@fedoraproject.org> - 2.6.1-2
- Rebuilt for https://fedoraproject.org/wiki/Fedora_30_Mass_Rebuild
* Tue Jan 15 2019 Elliott Sales de Andrade <quantum.analyst@gmail.com> - 2.6.1-1
- Update to latest version
* Mon Jan 14 2019 Elliott Sales de Andrade <quantum.analyst@gmail.com> - 2.5.2-4
- Rebuilt for dependencies
* Tue Oct 23 2018 Nicolas Mailhot <nim@fedoraproject.org>
- 2.5.2-3
- redhat-rpm-config-123 triggers bugs in gosetup, remove it from Go spec files as its just an alias
- https://lists.fedoraproject.org/archives/list/devel@lists.fedoraproject.org/message/RWD5YATAYAFWKIDZBB7EB6N5DAO4ZKFM/
* Fri Oct 12 2018 Elliott Sales de Andrade <quantum.analyst@gmail.com> - 2.5.2-2
- rebuilt
* Wed Oct 10 2018 Elliott Sales de Andrade <quantum.analyst@gmail.com> - 2.5.2-1
- Update to latest version
* Tue Sep 04 2018 Elliott Sales de Andrade <quantum.analyst@gmail.com> - 2.5.1-1
- Update to latest version
* Mon Sep 03 2018 Elliott Sales de Andrade <quantum.analyst@gmail.com> - 2.5.0-1
- Update to 2.5.0
* Wed Aug 29 2018 Elliott Sales de Andrade <quantum.analyst@gmail.com> - 2.4.2-1
- Update to 2.4.2
* Tue Jul 31 2018 Florian Weimer <fweimer@redhat.com> - 2.4.1-3
- Rebuild with fixed binutils
* Fri Jul 13 2018 Fedora Release Engineering <releng@fedoraproject.org> - 2.4.1-2
- Rebuilt for https://fedoraproject.org/wiki/Fedora_29_Mass_Rebuild

1
sources Normal file
View File

@ -0,0 +1 @@
SHA512 (git-lfs-v3.6.1.tar.gz) = 128dbcb503e71ccfc3aa97f92e191e1bed7432d7677723b518c86d211ad9660736dce1ac6ae94a1f7709567b7211c61885730f95ecea09f4aa4172e1c710d167