33set -e
44
55JSON_MODE=false
6+ DRY_RUN=false
67SHORT_NAME=" "
78BRANCH_NUMBER=" "
89USE_TIMESTAMP=false
@@ -14,6 +15,9 @@ while [ $i -le $# ]; do
1415 --json)
1516 JSON_MODE=true
1617 ;;
18+ --dry-run)
19+ DRY_RUN=true
20+ ;;
1721 --short-name)
1822 if [ $(( i + 1 )) -gt $# ]; then
1923 echo ' Error: --short-name requires a value' >&2
@@ -45,10 +49,11 @@ while [ $i -le $# ]; do
4549 USE_TIMESTAMP=true
4650 ;;
4751 --help|-h)
48- echo " Usage: $0 [--json] [--short-name <name>] [--number N] [--timestamp] <feature_description>"
52+ echo " Usage: $0 [--json] [--dry-run] [-- short-name <name>] [--number N] [--timestamp] <feature_description>"
4953 echo " "
5054 echo " Options:"
5155 echo " --json Output in JSON format"
56+ echo " --dry-run Compute branch name and paths without creating branches, directories, or files"
5257 echo " --short-name <name> Provide a custom short name (2-4 words) for the branch"
5358 echo " --number N Specify branch number manually (overrides auto-detection)"
5459 echo " --timestamp Use timestamp prefix (YYYYMMDD-HHMMSS) instead of sequential numbering"
6974
7075FEATURE_DESCRIPTION=" ${ARGS[*]} "
7176if [ -z " $FEATURE_DESCRIPTION " ]; then
72- echo " Usage: $0 [--json] [--short-name <name>] [--number N] [--timestamp] <feature_description>" >&2
77+ echo " Usage: $0 [--json] [--dry-run] [-- short-name <name>] [--number N] [--timestamp] <feature_description>" >&2
7378 exit 1
7479fi
7580
@@ -246,7 +251,19 @@ if [ "$USE_TIMESTAMP" = true ]; then
246251else
247252 # Determine branch number
248253 if [ -z " $BRANCH_NUMBER " ]; then
249- if [ " $HAS_GIT " = true ]; then
254+ if [ " $DRY_RUN " = true ]; then
255+ # Dry-run: use locally available data only (skip git fetch)
256+ _highest_branch=0
257+ if [ " $HAS_GIT " = true ]; then
258+ _highest_branch=$( get_highest_from_branches)
259+ fi
260+ _highest_spec=$( get_highest_from_specs " $SPECS_DIR " )
261+ _max_num=$_highest_branch
262+ if [ " $_highest_spec " -gt " $_max_num " ]; then
263+ _max_num=$_highest_spec
264+ fi
265+ BRANCH_NUMBER=$(( _max_num + 1 ))
266+ elif [ " $HAS_GIT " = true ]; then
250267 # Check existing branches on remotes
251268 BRANCH_NUMBER=$( check_existing_branches " $SPECS_DIR " )
252269 else
@@ -283,53 +300,70 @@ if [ ${#BRANCH_NAME} -gt $MAX_BRANCH_LENGTH ]; then
283300 >&2 echo " [specify] Truncated to: $BRANCH_NAME (${# BRANCH_NAME} bytes)"
284301fi
285302
286- if [ " $HAS_GIT " = true ]; then
287- if ! git checkout -b " $BRANCH_NAME " 2> /dev/null; then
288- # Check if branch already exists
289- if git branch --list " $BRANCH_NAME " | grep -q . ; then
290- if [ " $USE_TIMESTAMP " = true ]; then
291- >&2 echo " Error: Branch '$BRANCH_NAME ' already exists. Rerun to get a new timestamp or use a different --short-name."
303+ FEATURE_DIR=" $SPECS_DIR /$BRANCH_NAME "
304+ SPEC_FILE=" $FEATURE_DIR /spec.md"
305+
306+ if [ " $DRY_RUN " != true ]; then
307+ if [ " $HAS_GIT " = true ]; then
308+ if ! git checkout -b " $BRANCH_NAME " 2> /dev/null; then
309+ # Check if branch already exists
310+ if git branch --list " $BRANCH_NAME " | grep -q . ; then
311+ if [ " $USE_TIMESTAMP " = true ]; then
312+ >&2 echo " Error: Branch '$BRANCH_NAME ' already exists. Rerun to get a new timestamp or use a different --short-name."
313+ else
314+ >&2 echo " Error: Branch '$BRANCH_NAME ' already exists. Please use a different feature name or specify a different number with --number."
315+ fi
316+ exit 1
292317 else
293- >&2 echo " Error: Branch '$BRANCH_NAME ' already exists. Please use a different feature name or specify a different number with --number."
318+ >&2 echo " Error: Failed to create git branch '$BRANCH_NAME '. Please check your git configuration and try again."
319+ exit 1
294320 fi
295- exit 1
296- else
297- >&2 echo " Error: Failed to create git branch '$BRANCH_NAME '. Please check your git configuration and try again."
298- exit 1
299321 fi
322+ else
323+ >&2 echo " [specify] Warning: Git repository not detected; skipped branch creation for $BRANCH_NAME "
300324 fi
301- else
302- >&2 echo " [specify] Warning: Git repository not detected; skipped branch creation for $BRANCH_NAME "
303- fi
304325
305- FEATURE_DIR=" $SPECS_DIR /$BRANCH_NAME "
306- mkdir -p " $FEATURE_DIR "
326+ mkdir -p " $FEATURE_DIR "
307327
308- TEMPLATE=$( resolve_template " spec-template" " $REPO_ROOT " ) || true
309- SPEC_FILE=" $FEATURE_DIR /spec.md"
310- if [ -n " $TEMPLATE " ] && [ -f " $TEMPLATE " ]; then
311- cp " $TEMPLATE " " $SPEC_FILE "
312- else
313- echo " Warning: Spec template not found; created empty spec file" >&2
314- touch " $SPEC_FILE "
315- fi
328+ TEMPLATE=$( resolve_template " spec-template" " $REPO_ROOT " ) || true
329+ if [ -n " $TEMPLATE " ] && [ -f " $TEMPLATE " ]; then
330+ cp " $TEMPLATE " " $SPEC_FILE "
331+ else
332+ echo " Warning: Spec template not found; created empty spec file" >&2
333+ touch " $SPEC_FILE "
334+ fi
316335
317- # Inform the user how to persist the feature variable in their own shell
318- printf ' # To persist: export SPECIFY_FEATURE=%q\n' " $BRANCH_NAME " >&2
336+ # Inform the user how to persist the feature variable in their own shell
337+ printf ' # To persist: export SPECIFY_FEATURE=%q\n' " $BRANCH_NAME " >&2
338+ fi
319339
320340if $JSON_MODE ; then
321341 if command -v jq > /dev/null 2>&1 ; then
322- jq -cn \
323- --arg branch_name " $BRANCH_NAME " \
324- --arg spec_file " $SPEC_FILE " \
325- --arg feature_num " $FEATURE_NUM " \
326- ' {BRANCH_NAME:$branch_name,SPEC_FILE:$spec_file,FEATURE_NUM:$feature_num}'
342+ if [ " $DRY_RUN " = true ]; then
343+ jq -cn \
344+ --arg branch_name " $BRANCH_NAME " \
345+ --arg spec_file " $SPEC_FILE " \
346+ --arg feature_num " $FEATURE_NUM " \
347+ ' {BRANCH_NAME:$branch_name,SPEC_FILE:$spec_file,FEATURE_NUM:$feature_num,DRY_RUN:true}'
348+ else
349+ jq -cn \
350+ --arg branch_name " $BRANCH_NAME " \
351+ --arg spec_file " $SPEC_FILE " \
352+ --arg feature_num " $FEATURE_NUM " \
353+ ' {BRANCH_NAME:$branch_name,SPEC_FILE:$spec_file,FEATURE_NUM:$feature_num}'
354+ fi
327355 else
328- printf ' {"BRANCH_NAME":"%s","SPEC_FILE":"%s","FEATURE_NUM":"%s"}\n' " $( json_escape " $BRANCH_NAME " ) " " $( json_escape " $SPEC_FILE " ) " " $( json_escape " $FEATURE_NUM " ) "
356+ if [ " $DRY_RUN " = true ]; then
357+ 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 " ) "
358+ else
359+ printf ' {"BRANCH_NAME":"%s","SPEC_FILE":"%s","FEATURE_NUM":"%s"}\n' " $( json_escape " $BRANCH_NAME " ) " " $( json_escape " $SPEC_FILE " ) " " $( json_escape " $FEATURE_NUM " ) "
360+ fi
329361 fi
330362else
331363 echo " BRANCH_NAME: $BRANCH_NAME "
332364 echo " SPEC_FILE: $SPEC_FILE "
333365 echo " FEATURE_NUM: $FEATURE_NUM "
334- printf ' # To persist in your shell: export SPECIFY_FEATURE=%q\n' " $BRANCH_NAME "
366+ if [ " $DRY_RUN " != true ]; then
367+ printf ' # To persist in your shell: export SPECIFY_FEATURE=%q\n' " $BRANCH_NAME "
368+ fi
335369fi
0 commit comments