33set -e
44
55JSON_MODE=false
6+ DRY_RUN=false
67ALLOW_EXISTING=false
78SHORT_NAME=" "
89BRANCH_NUMBER=" "
@@ -15,6 +16,9 @@ while [ $i -le $# ]; do
1516 --json)
1617 JSON_MODE=true
1718 ;;
19+ --dry-run)
20+ DRY_RUN=true
21+ ;;
1822 --allow-existing-branch)
1923 ALLOW_EXISTING=true
2024 ;;
@@ -49,10 +53,11 @@ while [ $i -le $# ]; do
4953 USE_TIMESTAMP=true
5054 ;;
5155 --help|-h)
52- echo " Usage: $0 [--json] [--allow-existing-branch] [--short-name <name>] [--number N] [--timestamp] <feature_description>"
56+ echo " Usage: $0 [--json] [--dry-run] [-- allow-existing-branch] [--short-name <name>] [--number N] [--timestamp] <feature_description>"
5357 echo " "
5458 echo " Options:"
5559 echo " --json Output in JSON format"
60+ echo " --dry-run Compute branch name and paths without creating branches, directories, or files"
5661 echo " --allow-existing-branch Switch to branch if it already exists instead of failing"
5762 echo " --short-name <name> Provide a custom short name (2-4 words) for the branch"
5863 echo " --number N Specify branch number manually (overrides auto-detection)"
7479
7580FEATURE_DESCRIPTION=" ${ARGS[*]} "
7681if [ -z " $FEATURE_DESCRIPTION " ]; then
77- echo " Usage: $0 [--json] [--allow-existing-branch] [--short-name <name>] [--number N] [--timestamp] <feature_description>" >&2
82+ echo " Usage: $0 [--json] [--dry-run] [-- allow-existing-branch] [--short-name <name>] [--number N] [--timestamp] <feature_description>" >&2
7883 exit 1
7984fi
8085
@@ -251,7 +256,19 @@ if [ "$USE_TIMESTAMP" = true ]; then
251256else
252257 # Determine branch number
253258 if [ -z " $BRANCH_NUMBER " ]; then
254- if [ " $HAS_GIT " = true ]; then
259+ if [ " $DRY_RUN " = true ]; then
260+ # Dry-run: use locally available data only (skip git fetch)
261+ _highest_branch=0
262+ if [ " $HAS_GIT " = true ]; then
263+ _highest_branch=$( get_highest_from_branches)
264+ fi
265+ _highest_spec=$( get_highest_from_specs " $SPECS_DIR " )
266+ _max_num=$_highest_branch
267+ if [ " $_highest_spec " -gt " $_max_num " ]; then
268+ _max_num=$_highest_spec
269+ fi
270+ BRANCH_NUMBER=$(( _max_num + 1 ))
271+ elif [ " $HAS_GIT " = true ]; then
255272 # Check existing branches on remotes
256273 BRANCH_NUMBER=$( check_existing_branches " $SPECS_DIR " )
257274 else
@@ -288,62 +305,79 @@ if [ ${#BRANCH_NAME} -gt $MAX_BRANCH_LENGTH ]; then
288305 >&2 echo " [specify] Truncated to: $BRANCH_NAME (${# BRANCH_NAME} bytes)"
289306fi
290307
291- if [ " $HAS_GIT " = true ]; then
292- if ! git checkout -b " $BRANCH_NAME " 2> /dev/null; then
293- # Check if branch already exists
294- if git branch --list " $BRANCH_NAME " | grep -q . ; then
295- if [ " $ALLOW_EXISTING " = true ]; then
296- # Switch to the existing branch instead of failing
297- if ! git checkout " $BRANCH_NAME " 2> /dev/null; then
298- >&2 echo " Error: Failed to switch to existing branch '$BRANCH_NAME '. Please resolve any local changes or conflicts and try again."
308+ FEATURE_DIR=" $SPECS_DIR /$BRANCH_NAME "
309+ SPEC_FILE=" $FEATURE_DIR /spec.md"
310+
311+ if [ " $DRY_RUN " != true ]; then
312+ if [ " $HAS_GIT " = true ]; then
313+ if ! git checkout -b " $BRANCH_NAME " 2> /dev/null; then
314+ # Check if branch already exists
315+ if git branch --list " $BRANCH_NAME " | grep -q . ; then
316+ if [ " $ALLOW_EXISTING " = true ]; then
317+ # Switch to the existing branch instead of failing
318+ if ! git checkout " $BRANCH_NAME " 2> /dev/null; then
319+ >&2 echo " Error: Failed to switch to existing branch '$BRANCH_NAME '. Please resolve any local changes or conflicts and try again."
320+ exit 1
321+ fi
322+ elif [ " $USE_TIMESTAMP " = true ]; then
323+ >&2 echo " Error: Branch '$BRANCH_NAME ' already exists. Rerun to get a new timestamp or use a different --short-name."
324+ exit 1
325+ else
326+ >&2 echo " Error: Branch '$BRANCH_NAME ' already exists. Please use a different feature name or specify a different number with --number."
299327 exit 1
300328 fi
301- elif [ " $USE_TIMESTAMP " = true ]; then
302- >&2 echo " Error: Branch '$BRANCH_NAME ' already exists. Rerun to get a new timestamp or use a different --short-name."
303- exit 1
304329 else
305- >&2 echo " Error: Branch '$BRANCH_NAME ' already exists . Please use a different feature name or specify a different number with --number ."
330+ >&2 echo " Error: Failed to create git branch '$BRANCH_NAME '. Please check your git configuration and try again ."
306331 exit 1
307332 fi
308- else
309- >&2 echo " Error: Failed to create git branch '$BRANCH_NAME '. Please check your git configuration and try again."
310- exit 1
311333 fi
334+ else
335+ >&2 echo " [specify] Warning: Git repository not detected; skipped branch creation for $BRANCH_NAME "
312336 fi
313- else
314- >&2 echo " [specify] Warning: Git repository not detected; skipped branch creation for $BRANCH_NAME "
315- fi
316337
317- FEATURE_DIR=" $SPECS_DIR /$BRANCH_NAME "
318- mkdir -p " $FEATURE_DIR "
338+ mkdir -p " $FEATURE_DIR "
319339
320- SPEC_FILE= " $FEATURE_DIR /spec.md "
321- if [ ! -f " $SPEC_FILE " ] ; then
322- TEMPLATE= $( resolve_template " spec-template " " $REPO_ROOT " ) || true
323- if [ -n " $TEMPLATE " ] && [ -f " $TEMPLATE " ] ; then
324- cp " $TEMPLATE " " $SPEC_FILE "
325- else
326- echo " Warning: Spec template not found; created empty spec file " >&2
327- touch " $SPEC_FILE "
340+ if [ ! -f " $SPEC_FILE " ] ; then
341+ TEMPLATE= $( resolve_template " spec-template " " $REPO_ROOT " ) || true
342+ if [ -n " $TEMPLATE " ] && [ -f " $TEMPLATE " ] ; then
343+ cp " $TEMPLATE " " $SPEC_FILE "
344+ else
345+ echo " Warning: Spec template not found; created empty spec file " >&2
346+ touch " $SPEC_FILE "
347+ fi
328348 fi
329- fi
330349
331- # Inform the user how to persist the feature variable in their own shell
332- printf ' # To persist: export SPECIFY_FEATURE=%q\n' " $BRANCH_NAME " >&2
350+ # Inform the user how to persist the feature variable in their own shell
351+ printf ' # To persist: export SPECIFY_FEATURE=%q\n' " $BRANCH_NAME " >&2
352+ fi
333353
334354if $JSON_MODE ; then
335355 if command -v jq > /dev/null 2>&1 ; then
336- jq -cn \
337- --arg branch_name " $BRANCH_NAME " \
338- --arg spec_file " $SPEC_FILE " \
339- --arg feature_num " $FEATURE_NUM " \
340- ' {BRANCH_NAME:$branch_name,SPEC_FILE:$spec_file,FEATURE_NUM:$feature_num}'
356+ if [ " $DRY_RUN " = true ]; then
357+ jq -cn \
358+ --arg branch_name " $BRANCH_NAME " \
359+ --arg spec_file " $SPEC_FILE " \
360+ --arg feature_num " $FEATURE_NUM " \
361+ ' {BRANCH_NAME:$branch_name,SPEC_FILE:$spec_file,FEATURE_NUM:$feature_num,DRY_RUN:true}'
362+ else
363+ jq -cn \
364+ --arg branch_name " $BRANCH_NAME " \
365+ --arg spec_file " $SPEC_FILE " \
366+ --arg feature_num " $FEATURE_NUM " \
367+ ' {BRANCH_NAME:$branch_name,SPEC_FILE:$spec_file,FEATURE_NUM:$feature_num}'
368+ fi
341369 else
342- printf ' {"BRANCH_NAME":"%s","SPEC_FILE":"%s","FEATURE_NUM":"%s"}\n' " $( json_escape " $BRANCH_NAME " ) " " $( json_escape " $SPEC_FILE " ) " " $( json_escape " $FEATURE_NUM " ) "
370+ if [ " $DRY_RUN " = true ]; then
371+ printf ' {"BRANCH_NAME":"%s","SPEC_FILE":"%s","FEATURE_NUM":"%s","DRY_RUN":true}\n' " $( json_escape " $BRANCH_NAME " ) " " $( json_escape " $SPEC_FILE " ) " " $( json_escape " $FEATURE_NUM " ) "
372+ else
373+ printf ' {"BRANCH_NAME":"%s","SPEC_FILE":"%s","FEATURE_NUM":"%s"}\n' " $( json_escape " $BRANCH_NAME " ) " " $( json_escape " $SPEC_FILE " ) " " $( json_escape " $FEATURE_NUM " ) "
374+ fi
343375 fi
344376else
345377 echo " BRANCH_NAME: $BRANCH_NAME "
346378 echo " SPEC_FILE: $SPEC_FILE "
347379 echo " FEATURE_NUM: $FEATURE_NUM "
348- printf ' # To persist in your shell: export SPECIFY_FEATURE=%q\n' " $BRANCH_NAME "
380+ if [ " $DRY_RUN " != true ]; then
381+ printf ' # To persist in your shell: export SPECIFY_FEATURE=%q\n' " $BRANCH_NAME "
382+ fi
349383fi
0 commit comments