-
Notifications
You must be signed in to change notification settings - Fork 35
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
CG-13475: Fix checkout_branch to preserve changes when creating a new branch #931
Draft
codegen-sh
wants to merge
4
commits into
develop
Choose a base branch
from
fix-checkout-branch-preserve-changes
base: develop
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Conversation
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
I see there are merge conflicts in this PR. Here's a clean implementation of the fix that you can use to resolve the conflicts: def checkout_branch(self, branch_name: str | None, *, remote: bool = False, remote_name: str = "origin", create_if_missing: bool = True) -> CheckoutResult:
"""Attempts to check out the branch in the following order:
- Check out the local branch by name
- Check out the remote branch if it's been fetched
- Creates a new branch from the current commit (with create=True)
NOTE: if branch is already checked out this does nothing.
TIP: Use remote=True if you want to always try to checkout the branch from a remote
Args:
----
branch_name (str): Name of the branch to checkout.
create_if_missing: If the branch doesn't exist, create one
remote: Checks out a branch from a Remote + tracks the Remote
force (bool): If True, force checkout by resetting the current branch to HEAD.
If False, raise an error if the branch is dirty.
Raises:
------
GitCommandError: If there's an error with Git operations.
RuntimeError: If the branch is dirty and force is not set.
"""
if branch_name is None:
branch_name = self.default_branch
try:
if self.is_branch_checked_out(branch_name):
if remote:
# If the branch is already checked out and we want to fetch it from the remote, reset --hard to the remote branch
logger.info(f"Branch {branch_name} is already checked out locally. Resetting to remote branch: {remote_name}/{branch_name}")
# TODO: would have to fetch the the remote branch first to retrieve latest changes
self.git_cli.git.reset("--hard", f"{remote_name}/{branch_name}")
return CheckoutResult.SUCCESS
else:
logger.info(f"Branch {branch_name} is already checked out! Skipping checkout_branch.")
return CheckoutResult.SUCCESS
# Check if there are changes that need to be preserved
needs_stash = self.git_cli.is_dirty()
if needs_stash:
logger.info(f"Environment is dirty, stashing changes before checking out branch: {branch_name}.")
self.stash_push()
try:
# If remote=True, create a local branch tracking the remote branch and checkout onto it
if remote:
res = self.fetch_remote(remote_name, refspec=f"{branch_name}:{branch_name}")
if res is FetchResult.SUCCESS:
self.git_cli.git.checkout(branch_name)
if needs_stash:
logger.info(f"Applying stashed changes after checkout to branch: {branch_name}.")
self.stash_pop()
return CheckoutResult.SUCCESS
if res is FetchResult.REFSPEC_NOT_FOUND:
logger.warning(f"Branch {branch_name} not found in remote {remote_name}. Unable to checkout remote branch.")
if needs_stash:
logger.info("Restoring stashed changes.")
self.stash_pop()
return CheckoutResult.NOT_FOUND
# If the branch already exists, checkout onto it
if branch_name in self.git_cli.heads:
self.git_cli.heads[branch_name].checkout()
if needs_stash:
logger.info(f"Applying stashed changes after checkout to branch: {branch_name}.")
self.stash_pop()
return CheckoutResult.SUCCESS
# If the branch does not exist and create_if_missing=True, create and checkout a new branch from the current commit
elif create_if_missing:
logger.info(f"Creating new branch {branch_name} from current commit: {self.git_cli.head.commit.hexsha}")
new_branch = self.git_cli.create_head(branch_name)
new_branch.checkout()
if needs_stash:
logger.info(f"Applying stashed changes after checkout to new branch: {branch_name}.")
self.stash_pop()
return CheckoutResult.SUCCESS
else:
if needs_stash:
logger.info("Restoring stashed changes.")
self.stash_pop()
return CheckoutResult.NOT_FOUND
except Exception as e:
# If anything goes wrong, try to restore the stashed changes
if needs_stash:
try:
logger.info("An error occurred. Attempting to restore stashed changes.")
self.stash_pop()
except Exception as stash_error:
logger.error(f"Failed to restore stashed changes: {stash_error}")
raise e
except GitCommandError as e:
if "fatal: ambiguous argument" in e.stderr:
logger.warning(f"Branch {branch_name} was not found in remote {remote_name}. Unable to checkout.")
return CheckoutResult.NOT_FOUND
else:
logger.exception(f"Error with Git operations: {e}")
raise This implementation:
The key difference from the current implementation is that it always preserves changes instead of discarding them, which fixes the issue described in CG-13474. |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Labels
None yet
0 participants
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Problem
Currently, when using the
checkout_branch
tool withcreate_if_missing=True
, it discards all existing changes before creating the new branch. This causes only new files to show up in PRs, while modifications to existing files are lost.The issue is in the
checkout_branch
method insrc/codegen/git/repo_operator/repo_operator.py
where it callsdiscard_changes()
when the environment is dirty (lines 418-420).Solution
This PR modifies the
checkout_branch
method to:This ensures that all changes (both new files and modifications to existing files) are preserved when creating a new branch.
The key changes are:
Fixes CG-13475