@@ -694,6 +694,10 @@ func (r *gitRepo) ReadZip(rev, subdir string, maxSize int64) (zip io.ReadCloser,
694
694
return nil , "" , err
695
695
}
696
696
697
+ if err := ensureGitAttributes (r .dir ); err != nil {
698
+ return nil , "" , err
699
+ }
700
+
697
701
// Incredibly, git produces different archives depending on whether
698
702
// it is running on a Windows system or not, in an attempt to normalize
699
703
// text file line endings. Setting -c core.autocrlf=input means only
@@ -709,3 +713,43 @@ func (r *gitRepo) ReadZip(rev, subdir string, maxSize int64) (zip io.ReadCloser,
709
713
710
714
return ioutil .NopCloser (bytes .NewReader (archive )), "" , nil
711
715
}
716
+
717
+ // ensureGitAttributes makes sure export-subst and export-ignore features are
718
+ // disabled for this repo. This is intended to be run prior to running git
719
+ // archive so that zip files are generated that produce consistent ziphashes
720
+ // for a given revision, independent of variables such as git version and the
721
+ // size of the repo.
722
+ //
723
+ // See: https://github.com/golang/go/issues/27153
724
+ func ensureGitAttributes (repoDir string ) (err error ) {
725
+ const attr = "\n * -export-subst -export-ignore\n "
726
+
727
+ d := repoDir + "/info"
728
+ p := d + "/attributes"
729
+
730
+ if err := os .MkdirAll (d , 0755 ); err != nil {
731
+ return err
732
+ }
733
+
734
+ f , err := os .OpenFile (p , os .O_CREATE | os .O_APPEND | os .O_RDWR , 0666 )
735
+ if err != nil {
736
+ return err
737
+ }
738
+ defer func () {
739
+ closeErr := f .Close ()
740
+ if closeErr != nil {
741
+ err = closeErr
742
+ }
743
+ }()
744
+
745
+ b , err := ioutil .ReadAll (f )
746
+ if err != nil {
747
+ return err
748
+ }
749
+ if ! bytes .HasSuffix (b , []byte (attr )) {
750
+ _ , err := f .WriteString (attr )
751
+ return err
752
+ }
753
+
754
+ return nil
755
+ }
0 commit comments