Skip to content

Commit 573997b

Browse files
committed
Don't initialize a new git repo if one exists in the parent path(s).
1 parent 50c3ab1 commit 573997b

File tree

3 files changed

+51
-13
lines changed

3 files changed

+51
-13
lines changed

agentstack/cli/init.py

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -135,12 +135,21 @@ def init_project(
135135
packaging.create_venv()
136136
log.info("Installing dependencies...")
137137
packaging.install_project()
138-
repo.init() # initialize git repo
138+
139+
if repo.find_parent_repo(conf.PATH):
140+
# if a repo already exists, we don't want to initialize a new one
141+
log.info("Found existing git repository; disabling tracking.")
142+
with conf.ConfigFile() as config:
143+
config.use_git = False
144+
else:
145+
# create a new git repo in the project dir
146+
repo.init()
139147

140148
# now we can interact with the project and add Agents, Tasks, and Tools
141149
# we allow dependencies to be installed along with these, so the project must
142150
# be fully initialized first.
143151
with repo.Transaction() as commit:
152+
commit.add_message("Initialized new project")
144153
for task in template_data.tasks:
145154
commit.add_message(f"Added task {task.name}")
146155
generation.add_task(**task.model_dump())

agentstack/repo.py

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
from typing import Optional
2+
from pathlib import Path
13
import shutil
24
import git
35
from agentstack import conf, log
@@ -108,6 +110,18 @@ def _require_git():
108110
raise EnvironmentError(message)
109111

110112

113+
def find_parent_repo(path: Path) -> Optional[Path]:
114+
"""
115+
Traverse the directory tree upwards from `path` until a .git directory is found.
116+
"""
117+
current = path.absolute()
118+
while current != current.parent:
119+
if (current / '.git').exists():
120+
return current
121+
current = current.parent
122+
return None
123+
124+
111125
def _get_repo() -> git.Repo:
112126
"""
113127
Get the git repository for the current project.
@@ -118,22 +132,31 @@ def _get_repo() -> git.Repo:
118132
"""
119133
_require_git()
120134
try:
135+
# look for a repository in the project's directory
121136
return git.Repo(conf.PATH.absolute())
122137
except git.exc.InvalidGitRepositoryError:
123138
message = "No git repository found in the current project."
124139
log.warning(message) # log now since this won't bubble to the user
125140
raise EnvironmentError(message)
126141

127142

128-
def init() -> None:
143+
def init(force_creation: bool = False) -> None:
129144
"""
130145
Create a git repository for the current project and commit a .gitignore file
131-
to initialize the repo. Assumes that a repo does not already exist.
146+
to initialize the repo.
147+
148+
`force_creation` will create a new repo even if one already exists in a parent
149+
directory. default: False
132150
"""
133151
try:
134152
_require_git()
135153
except EnvironmentError as e:
136154
return # git is not installed or tracking is disabled
155+
156+
if find_parent_repo(conf.PATH.absolute()):
157+
log.warning("A git repository already exists in a parent directory.")
158+
if not force_creation:
159+
return
137160

138161
# creates a new repo at conf.PATH / '.git
139162
repo = git.Repo.init(path=conf.PATH.absolute(), initial_branch=MAIN_BRANCH_NAME)

tests/test_repo.py

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ def tearDown(self):
2828
shutil.rmtree(self.test_dir)
2929

3030
def test_init(self):
31-
repo.init()
31+
repo.init(force_creation=True)
3232

3333
# Check if a git repository was created
3434
self.assertTrue((self.test_dir / '.git').is_dir())
@@ -40,19 +40,25 @@ def test_init(self):
4040
self.assertEqual(len(commits), 1)
4141
self.assertEqual(commits[0].message, f"{repo.INITIAL_COMMIT_MESSAGE}{repo.AUTOMATION_NOTE}")
4242

43+
def test_init_parent_repo_exists(self):
44+
os.makedirs(self.test_dir.parent / '.git')
45+
46+
repo.init(force_creation=False)
47+
self.assertFalse((self.test_dir / '.git').is_dir())
48+
4349
def test_get_repo_nonexistent(self):
4450
with self.assertRaises(EnvironmentError):
4551
repo._get_repo()
4652

4753
def test_get_repo_existent(self):
48-
repo.init()
54+
repo.init(force_creation=True)
4955

5056
result = repo._get_repo()
5157
self.assertIsInstance(result, git.Repo)
5258
self.assertEqual(result.working_tree_dir, str(self.test_dir))
5359

5460
def test_get_uncommitted_files_new_file(self):
55-
repo.init()
61+
repo.init(force_creation=True)
5662

5763
new_file = self.test_dir / "new_file.txt"
5864
new_file.touch()
@@ -62,7 +68,7 @@ def test_get_uncommitted_files_new_file(self):
6268
self.assertIn("new_file.txt", uncommitted)
6369

6470
def test_get_uncommitted_files_modified_file(self):
65-
repo.init()
71+
repo.init(force_creation=True)
6672

6773
# Create and commit an initial file
6874
initial_file = self.test_dir / "initial_file.txt"
@@ -154,7 +160,7 @@ def test_require_git_installed(self, mock_which, mock_should_track):
154160
repo._require_git()
155161

156162
def test_transaction_context_manager(self):
157-
repo.init()
163+
repo.init(force_creation=True)
158164
mock_commit = MagicMock()
159165

160166
with patch('agentstack.repo.commit', mock_commit):
@@ -165,7 +171,7 @@ def test_transaction_context_manager(self):
165171
mock_commit.assert_called_once_with(f"Test message", ["test_file.txt"], automated=True)
166172

167173
def test_transaction_multiple_messages(self):
168-
repo.init()
174+
repo.init(force_creation=True)
169175
mock_commit = MagicMock()
170176

171177
with patch('agentstack.repo.commit', mock_commit):
@@ -180,7 +186,7 @@ def test_transaction_multiple_messages(self):
180186
)
181187

182188
def test_transaction_no_changes(self):
183-
repo.init()
189+
repo.init(force_creation=True)
184190
mock_commit = MagicMock()
185191

186192
with patch('agentstack.repo.commit', mock_commit):
@@ -192,7 +198,7 @@ def test_transaction_no_changes(self):
192198
mock_commit.assert_not_called()
193199

194200
def test_transaction_with_exception(self):
195-
repo.init()
201+
repo.init(force_creation=True)
196202
mock_commit = MagicMock()
197203

198204
with patch('agentstack.repo.commit', mock_commit):
@@ -212,7 +218,7 @@ def test_transaction_with_exception(self):
212218

213219
def test_init_when_git_disabled(self):
214220
repo.dont_track_changes()
215-
result = repo.init()
221+
result = repo.init(force_creation=True)
216222
self.assertIsNone(result)
217223
repo._USE_GIT = None # Reset for other tests
218224

@@ -235,7 +241,7 @@ def test_get_uncommitted_files_when_git_disabled(self):
235241
repo._USE_GIT = None # Reset for other tests
236242

237243
def test_commit_user_changes(self):
238-
repo.init()
244+
repo.init(force_creation=True)
239245

240246
# Create a new file
241247
test_file = self.test_dir / "user_file.txt"

0 commit comments

Comments
 (0)