Skip to content

git: worktree, Don't delete local untracked files when resetting worktree #1540

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 2 commits into
base: main
Choose a base branch
from

Conversation

k-anshul
Copy link

@k-anshul k-anshul commented May 2, 2025

Fixes #53

@Copilot Copilot AI review requested due to automatic review settings May 2, 2025 09:25
@k-anshul k-anshul changed the title git: worktree, Don't delete local untracked files when resetting work… git: worktree, Don't delete local untracked files when resetting worktree May 2, 2025
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 refines the worktree reset functionality so that local untracked files are preserved when resetting the worktree, addressing issue #53.

  • Updates the test in worktree_test.go to verify that untracked files (e.g. "foo") remain unaltered.
  • Modifies the ResetSparsely, resetIndex, and resetWorktree functions in worktree.go to track removed files and adjust the file checkout logic based on untracked status.

Reviewed Changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.

File Description
worktree_test.go Replaces a simple IsClean assertion with a loop to validate specific file statuses.
worktree.go Returns removed file information from resetIndex and uses it in resetWorktree to decide which files to check out.

continue
}
if st.Worktree != Unmodified || st.Staging != Unmodified {
s.Fail("file %s not unmodified", file)
Copy link
Preview

Copilot AI May 2, 2025

Choose a reason for hiding this comment

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

It appears that s.Fail is being used with a format string; consider using s.Failf to properly format error messages.

Suggested change
s.Fail("file %s not unmodified", file)
s.Failf("file %s not unmodified", file)

Copilot uses AI. Check for mistakes.

// only checkout an untracked file if it is in the list of files
// a reset should leave untracked files alone
file := nameFromAction(&ch)
if status.File(file).Worktree != Untracked || inFiles(files, file) {
Copy link
Preview

Copilot AI May 2, 2025

Choose a reason for hiding this comment

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

[nitpick] The compound conditional here could be refactored into a well-named variable or helper function to enhance readability.

Suggested change
if status.File(file).Worktree != Untracked || inFiles(files, file) {
if shouldCheckoutChange(status, file, files) {

Copilot uses AI. Check for mistakes.

// only checkout an untracked file if it is in the list of files
// a reset should leave untracked files alone
file := nameFromAction(&ch)
if status.File(file).Worktree != Untracked || inFiles(files, file) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Can we use ch instead of status? I think something like

action, err := ch.Action()
if err != nil {
	return err
}

if action != merkletrie.Insert {
    // checkout the file
}

Would work since "Untracked" would mean that the file appears in worktree but not in staging.

For reference, Status() also works this way internally.

go-git/worktree_status.go

Lines 93 to 118 in 93ed29d

right, err := w.diffStagingWithWorktree(false, true)
if err != nil {
return nil, err
}
for _, ch := range right {
a, err := ch.Action()
if err != nil {
return nil, err
}
fs := s.File(nameFromAction(&ch))
if fs.Staging == Untracked {
fs.Staging = Unmodified
}
switch a {
case merkletrie.Delete:
fs.Worktree = Deleted
case merkletrie.Insert:
fs.Worktree = Untracked
fs.Staging = Untracked
case merkletrie.Modify:
fs.Worktree = Modified
}
}

This way we can avoid re-doing computations that we already have done.

// only checkout an untracked file if it is in the list of files
// a reset should leave untracked files alone
file := nameFromAction(&ch)
if status.File(file).Worktree != Untracked || inFiles(files, file) {
Copy link
Contributor

@onee-only onee-only May 2, 2025

Choose a reason for hiding this comment

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

Is there any specific reason that we check inFiles here? I think it is already done in block above.
I wasn't paying attention to the comment. Sorry for the confusion.

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.

Pull removes untracked files locally
2 participants