Skip to content

Preserve local changes option #2239

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 8 commits into
base: main
Choose a base branch
from

Conversation

salmanmkc
Copy link
Contributor

New option for the GitHub Actions checkout process, allowing users to preserve local files that are not tracked by Git during a checkout. The changes span documentation, configuration, and implementation, ensuring users can opt-in to this behavior via a new preserve-local-changes input. The implementation carefully handles file restoration and updates relevant interfaces and workflow examples.

For this #2216 & this #2054

You can test it with this branch/workflow file:

name: Test Preserve Local Changes
on:
  workflow_dispatch:

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - name: Create local file
        shell: bash
        run: |
          echo "This is a test file" > example.txt
          ls -la
          echo "File created successfully"
      
      - name: Checkout
        uses: salmanmkc/checkout@preservelocalchanges
        with:
          clean: false
          preserve-local-changes: true
      
      - name: Verify file exists after checkout
        shell: bash
        run: |
          echo "Checking if example.txt still exists after checkout:"
          if [ -f "example.txt" ]; then
            echo "SUCCESS: File was preserved"
            cat example.txt
          else
            echo "FAILURE: File was removed"
          fi
          
      - name: List all files for debugging
        shell: bash
        run: |
          echo "Listing all files in the directory:"
          ls -la

@Copilot Copilot AI review requested due to automatic review settings August 11, 2025 11:44
Copy link

@Copilot Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR adds a new preserve-local-changes option to the GitHub Actions checkout process that allows users to preserve local files that are not tracked by Git during checkout. The feature addresses issues where local files created before checkout would be lost.

  • Adds preserve-local-changes input parameter with default value of false
  • Implements file preservation logic that stores local files in memory before checkout and restores untracked files after checkout
  • Updates interfaces, documentation, and workflow examples to support the new feature

Reviewed Changes

Copilot reviewed 7 out of 8 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
action.yml Adds new preserve-local-changes input parameter with documentation
README.md Documents the new feature with usage examples
src/input-helper.ts Parses the new input parameter from action configuration
src/git-source-settings.ts Adds preserveLocalChanges property to the settings interface
src/git-source-provider.ts Implements core file preservation logic during checkout
src/git-directory-helper.ts Modifies directory cleanup to respect preserve settings
src/git-command-manager.ts Updates checkout method to support custom options


// List and store local files before checkout
const fs = require('fs')
const path = require('path')
Copy link
Preview

Copilot AI Aug 11, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Import statements should be at the top of the file using ES6 import syntax instead of require() within function scope.

Suggested change
const path = require('path')

Copilot uses AI. Check for mistakes.

for (const [filePath, content] of localFiles.entries()) {
// Check if file exists in git using a child process instead of git.execGit
const { exec } = require('@actions/exec')
let exitCode = 0
Copy link
Preview

Copilot AI Aug 11, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Import statements should be at the top of the file using ES6 import syntax instead of require() within function scope.

Suggested change
let exitCode = 0
let exitCode = 0

Copilot uses AI. Check for mistakes.

}
})
return results
}
Copy link
Preview

Copilot AI Aug 11, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using synchronous file operations (readFileSync, readdirSync, statSync) can block the event loop. Consider using async versions with await to maintain performance in Node.js applications.

Copilot uses AI. Check for mistakes.


const localFilesList = listFilesRecursively(workspacePath)
core.info(`Found ${localFilesList.length} local files to preserve:`)
localFilesList.forEach(file => core.info(` - ${file}`))
Copy link
Preview

Copilot AI Aug 11, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reading all files into memory simultaneously could cause high memory usage for repositories with large files. Consider implementing a streaming approach or processing files in batches.

Suggested change
localFilesList.forEach(file => core.info(` - ${file}`))
// Store only file path, not content
results.push(relativePath)
}
})
return results
}
const localFilesList = listFilesRecursively(workspacePath)
localFilesList.forEach(file => localFilePaths.push(file))
core.info(`Found ${localFilePaths.length} local files to preserve:`)
localFilePaths.forEach(file => core.info(` - ${file}`))

Copilot uses AI. Check for mistakes.

// We still need to make sure we have a git repository to work with
if (!git) {
core.info(`Initializing git repository to prepare for checkout with preserved changes`)
await fs.promises.mkdir(path.join(repositoryPath, '.git'), { recursive: true })
Copy link
Preview

Copilot AI Aug 11, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Creating only the .git directory is insufficient to initialize a proper Git repository. This should use git init command or proper Git initialization to create all necessary Git metadata files.

Suggested change
await fs.promises.mkdir(path.join(repositoryPath, '.git'), { recursive: true })
await new Promise<void>((resolve, reject) => {
execFile('git', ['init'], { cwd: repositoryPath }, (error) => {
if (error) {
reject(error)
} else {
resolve()
}
})
})

Copilot uses AI. Check for mistakes.

Makes preserve-local-changes option work consistently in all scenarios,
including when repository URL changes. Updates warning message to
correctly reflect this behavior.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant