@@ -41,6 +41,80 @@ def get_latest_git_revision(branch_name):
4141 except subprocess .CalledProcessError as e :
4242 raise Exception (f"Failed to get the latest revision for branch '{ branch_name } '." ) from e
4343
44+
45+ def get_trigger_branch (repo , default_branch ):
46+ """
47+ Gets the trigger branch name, handling detached HEAD state in CI environments.
48+
49+ In CI environments, the repository might be checked out at a specific commit (detached HEAD).
50+ This function tries multiple methods to determine the branch:
51+ 1. Check if HEAD is attached to a branch
52+ 2. Check environment variables (YAMATO_BRANCH, CI_COMMIT_REF_NAME, etc.)
53+ 3. Use git commands to find which remote branch contains the current commit
54+ 4. Fall back to the default branch if nothing else works
55+
56+ Args:
57+ repo: GitPython Repo object
58+ default_branch: Default branch name to fall back to
59+
60+ Returns:
61+ str: The branch name
62+ """
63+ try :
64+ # Try to get the active branch name (works when HEAD is attached)
65+ return repo .active_branch .name
66+ except (TypeError , ValueError ):
67+ # HEAD is detached, try other methods
68+ pass
69+
70+ # Method 1: Check environment variables
71+ # Yamato might set branch info in environment variables
72+ trigger_branch = os .environ .get ('YAMATO_BRANCH' ) or \
73+ os .environ .get ('CI_COMMIT_REF_NAME' ) or \
74+ os .environ .get ('GITHUB_REF_NAME' ) or \
75+ os .environ .get ('BRANCH_NAME' )
76+
77+ if trigger_branch :
78+ # Remove 'refs/heads/' prefix if present
79+ trigger_branch = trigger_branch .replace ('refs/heads/' , '' )
80+ print (f"Found trigger branch from environment variable: { trigger_branch } " )
81+ return trigger_branch
82+
83+ # Method 2: Try to find which remote branch contains the current commit
84+ try :
85+ current_commit = repo .head .commit .hexsha
86+ # Fetch all remote branches
87+ repo .git .fetch ('origin' , '--prune' , '--prune-tags' )
88+
89+ # Try to find which remote branch points to this commit
90+ result = subprocess .run (
91+ ['git' , 'branch' , '-r' , '--contains' , current_commit ],
92+ capture_output = True ,
93+ text = True ,
94+ check = True
95+ )
96+
97+ branches = [b .strip () for b in result .stdout .strip ().split ('\n ' ) if b .strip ()]
98+ # Filter to find the most likely branch (prefer default branch, then develop, then others)
99+ for branch_line in branches :
100+ branch = branch_line .replace ('origin/' , '' ).strip ()
101+ if branch and branch == default_branch :
102+ print (f"Found trigger branch from remote branches: { branch } " )
103+ return branch
104+
105+ # If default branch not found, use the first one
106+ if branches :
107+ branch = branches [0 ].replace ('origin/' , '' ).strip ()
108+ if branch :
109+ print (f"Found trigger branch from remote branches: { branch } " )
110+ return branch
111+ except Exception as e :
112+ print (f"Warning: Could not determine branch from remote branches: { e } " )
113+
114+ # Method 3: Fall back to default branch
115+ print (f"Warning: Could not determine trigger branch, falling back to default branch: { default_branch } " )
116+ return default_branch
117+
44118def create_release_branch (config : ReleaseConfig ):
45119 """
46120 Creates a new branch with the specified name, performs specified action, commits the current changes and pushes it to the repo.
@@ -56,7 +130,16 @@ def create_release_branch(config: ReleaseConfig):
56130 raise Exception (f"Branch '{ config .release_branch_name } ' already exists." )
57131
58132 repo = get_local_repo ()
59- trigger_branch = repo .active_branch .name
133+ trigger_branch = get_trigger_branch (repo , config .default_repo_branch )
134+ print (f"\n Trigger branch: { trigger_branch } " )
135+
136+ # If we're in detached HEAD state, checkout the trigger branch first
137+ try :
138+ repo .active_branch .name
139+ except (TypeError , ValueError ):
140+ # HEAD is detached, checkout the trigger branch
141+ print (f"HEAD is detached, checking out trigger branch '{ trigger_branch } '..." )
142+ repo .git .checkout (trigger_branch )
60143
61144 # Stash any uncommitted changes to allow pull
62145 has_uncommitted_changes = repo .is_dirty ()
0 commit comments