# Git Workflow FAQ

## Q1 – When to use tags?

Use **tags** to mark **specific commits as releases or milestones**, not for ongoing work.

Typical use cases:

- Marking versioned releases: `v1.0.0`, `v2.3.1`
- Marking deployment points: `prod-2025-09-10`
- Marking important states: `pre-refactor`, `before-db-migration`

Rules of thumb:

- **Branch** for lines of development (features, releases you're still working on).
- **Tag** for fixed points you want to refer to forever (released versions).

You do **not** need a tag for every commit; just for versions you care about as "this is what we shipped".

---

## Q2 – When to change branch? One branch per major version (2.0, 3.0)?

It depends on how many versions you need to **maintain in parallel**.

### Common patterns

**1. Single active version (simplest, often best)**  
- Only `main` is used for development.
- Each release is a **tag** on `main`: `v1.0.0`, `v1.1.0`, `v2.0.0`.
- No long‑lived version branches.
- Use this unless you must support old versions at the same time.

**2. Major version branches (when you must maintain multiple majors)**  
- `main` = current development (e.g., heading toward 3.0).
- `2.x` branch = maintenance for the 2.0 line.
- `3.x` branch (later) = maintenance for the 3.0 line.
- You create a new branch when you need to:
  - Keep developing on a new major version, and
  - Still release bugfixes for the previous major without mixing in breaking changes.

Rule:  
- If you only ever deploy **one version at a time**, you usually don't need version branches; tags on `main` are enough.  
- If you must support **2.0 and 3.0 simultaneously in production**, then have `2.x` and `3.x` branches and tag releases on each.

---

## Q4 – How to check repository files, dates, sizes, versions?

### List tracked files with last commit date

From a working copy:

```bash
# File, last commit date, relative path
git log --format='%ad' --date=short --name-only -- . | \
  awk 'NF==1 && !seen[$0]++ {file=$0} NF>1 {print $0, file}' | \
  sort
```

Simpler, per-file:

```bash
git log -1 --format='%ad' --date=short -- path/to/file
```

### Files with sizes (working tree)

```bash
git ls-files | xargs ls -lSh
```

This shows tracked files with sizes, sorted by size.

### Largest files ever in history

```bash
git rev-list --objects --all |
  git cat-file --batch-check='%(objecttype) %(objectname) %(objectsize) %(rest)' |
  sed -n 's/^blob //p' |
  sort -k2 -nr |
  head -n 20
```

Shows the 20 largest blobs ever committed.

### "Versions" in Git terms

Git doesn't store a version number inside each file; version is represented by:

- **Tags**: `v1.2.3`
- **Commits**: SHA or `HEAD~3`, etc.

To see which tag a file belongs to:

```bash
git describe --tags --always
# or for a specific file at current HEAD:
git log -1 --decorate --oneline -- path/to/file
```

---

## Q5 – How to get version number and filename auto‑installed in each file?

Git itself **does not** expand version/file macros inside files on checkout (unlike old SVN `$Id$` keywords). The usual approaches:

### A. Store version in a single source of truth

Keep a `VERSION` file (or in code, e.g., `config/version.php`):

```bash
echo "1.2.3" > VERSION
git add VERSION
git commit -m "Bump version to 1.2.3"
git tag -a v1.2.3 -m "Release 1.2.3"
git push origin main --tags
```

Your app reads this file (or a generated constant) at runtime.

### B. Generate files at build/deploy time

Instead of embedding version in every file manually:

- Have a template like `version.txt.in` or `config.php.in`.
- At build/deploy, substitute placeholders:

  ```bash
  VERSION=$(cat VERSION)
  sed "s/%%VERSION%%/$VERSION/" version.txt.in > version.txt
  ```

This is more robust than trying to keep version strings updated in many files.

### C. If you really want per-file version headers

Write a small script that:

1. Reads `VERSION`.
2. Rewrites headers in your source files (e.g., PHP comment block at top).
3. Commits them.

But this tends to cause noisy commits; most teams avoid it.

---

## `git-bump-version` script: usage and syntax

You already have `git-bump-version` in `git-tools.zip`. Here's how to use it.

### Basic usage

From inside a repo working copy:

```bash
# Auto-increment patch: 1.2.3 -> 1.2.4
./git-bump-version

# Specify version explicitly
./git-bump-version 1.3.0

# With explicit repo path (uses DEFAPP or 'defapp' if omitted)
./git-bump-version 1.3.0 ./app1
```

What it does:

- Reads/creates `VERSION` file.
- Writes the new version into `VERSION`.
- Commits that change.
- Creates an annotated tag `v<version>` (if it doesn't already exist).

### Example sequence

```bash
# Current version in VERSION is 1.2.3
./git-bump-version
# -> creates VERSION=1.2.4, commits, tags v1.2.4

# Now push everything
git push
git push --tags
```

If you want, I can extend `git-bump-version` to:

- Accept a `--no-tag` mode.
- Update a version constant in a specific file (e.g., `config/version.php`) in addition to `VERSION`.
