Files
retroSoC/docs/git-workflow.md

245 lines
9.6 KiB
Markdown

# Git Development Workflow
This document defines Git practices for retroSoC contributors and maintainers.
See [Contributing](../CONTRIBUTING.md) for discussion, review, and validation
responsibilities. Run the examples deliberately, one step at a time; stop and
inspect any failure before continuing. They assume Git is installed and the
working directory is the repository root unless stated otherwise. Replace
example account, branch, path, and commit values with your own.
## Branches and integration
| Branch | Purpose and ownership |
| --- | --- |
| `main` | Maintainer-controlled release integration. Ordinary contributions do not target this branch. |
| `dev` | Shared integration branch and default base for contribution PRs. |
| `<type>/<short-topic>` | Short-lived branch for one contribution or reviewable feature phase. |
Use lowercase, hyphen-separated topics, such as `feat/apu-stream`,
`fix/quality-format`, or `docs/contributing`. Start new work from the current
remote `dev`; do not use a local `dev` containing unrelated commits as the
base. Document dependencies if a stacked PR needs another topic branch.
Contributions enter `dev` through PRs, normally using **Create a merge commit**
to retain meaningful individual commits. Keep separate phase commits when
they aid review and diagnosis. Do not rewrite `dev` or `main`, force-push to
them, or use a direct push to bypass review. Maintainers manage release PRs
from `dev` into `main`; a release integration is not proof of hardware signoff.
These are collaboration rules, not a claim about enabled GitHub protection
settings.
## Start a contribution
### External contributors: fork workflow
Fork the repository on GitHub first. In this example, `YOUR-USER` is your
account, `origin` is your fork, and `upstream` is the canonical repository.
```sh
git clone https://github.com/YOUR-USER/retroSoC.git
cd retroSoC
git remote add upstream https://github.com/retroSoC/retroSoC.git
git remote -v
git fetch upstream
git switch --no-track -c fix/quality-format upstream/dev
```
Make and validate the change, commit it as described below, then publish the
topic branch to your fork:
```sh
git push -u origin fix/quality-format
```
Open a PR from your fork's topic branch to **retroSoC/retroSoC:dev**, using the
repository's [PR template](../.github/pull_request_template.md).
### Maintainers: canonical clone
For a canonical clone, `origin` is the project repository; an `upstream`
remote is not required. Check the URL before pushing.
```sh
git clone https://github.com/retroSoC/retroSoC.git
cd retroSoC
git remote -v
git fetch origin
git switch --no-track -c fix/quality-format origin/dev
```
After committing and validating, push with
`git push -u origin fix/quality-format` and open a PR to `dev`. Write access
does not replace review.
## Commit conventions
Use `type(scope): summary`; the scope is optional. Use `feat`, `fix`, `docs`,
`test`, `refactor`, `build`, `ci`, `perf`, `chore`, or `revert` as appropriate.
Examples:
```text
fix(apu): reject a misaligned output buffer
docs: explain contribution validation
ci: prepare locked simulation fixtures
```
Write a concise English summary of what changes. Use the body to explain why,
compatibility implications, and relevant evidence. Reference related issues
or specifications; use a closing reference only when the change actually
resolves the issue. Explain breaking changes explicitly in both the commit
body and PR rather than relying on the title alone. Git-generated merge and
revert subjects may retain their standard form.
Each commit should represent one coherent, reviewable change. Keep unrelated
formatting, generated baseline updates, and functional work separate. Do not
commit credentials, ignored build outputs, caches, or managed checkouts.
Review the index rather than assuming that every working-tree edit belongs
in the commit:
```sh
git status --short --branch
git diff
git add -- path/to/changed-file
git diff --cached
git diff --cached --check
git commit -m "fix(scope): describe the change"
```
The path and message above are placeholders. Add each intended new or modified
file explicitly, and follow the repository's applicable validation requirements.
## Synchronize and resolve conflicts
### Save unfinished work first
Before switching branches or integrating updates, inspect `git status`,
`git diff`, and `git diff --cached`. Prefer a meaningful local commit when
the change is ready. Otherwise, save unfinished work:
```sh
git stash push -u -m "before syncing contribution"
git stash list
git status --short --branch
```
`-u` includes untracked files but excludes ignored files and changes inside
nested repositories. Save any such work separately if it matters. Continue
only after checking that Git saved the intended changes and the working tree
is ready for integration. Record which stash you created; later examples use
`stash@{0}` only if it is still that entry.
### Update a shared topic branch
Remain on your topic branch. If it is already published, first incorporate
changes pushed by collaborators to that topic. In both clone examples,
`origin` is the remote where you publish it:
```sh
git fetch origin
git log --oneline --left-right HEAD...origin/fix/quality-format
git merge origin/fix/quality-format
```
Skip this block if the topic has not been published yet. Resolve any conflicts
using the steps below before proceeding. Then integrate canonical `dev`.
For a fork:
```sh
git fetch upstream
git merge upstream/dev
```
In a canonical clone, use `git fetch origin` and `git merge origin/dev`.
Merge preserves published commits and other contributors' work. When updating
a local `dev` with no local-only commits, use `git merge --ff-only origin/dev`
(or `upstream/dev` for a fork). If that fails, inspect the divergence rather
than resetting away local commits.
After integration, rerun affected checks and push the topic normally. If the
push is rejected because the remote advanced again, fetch, inspect, and merge
those changes; do not force-push around the rejection.
If a merge conflicts:
1. Run `git status` and `git diff --name-only --diff-filter=U`.
2. Edit each conflicted file, reconcile both sides' intent, and remove conflict
markers. Review dependency entries and interface changes semantically; do
not select an entire side merely to silence the conflict.
3. Stage the resolved paths with `git add -- path/to/resolved-file`, inspect
`git diff --cached`, and run the affected validation.
4. Complete the merge with `git merge --continue`. To abandon the in-progress
merge, use `git merge --abort` before restoring your stash.
### Restore unfinished work
After a successful integration, restore the recorded stash without deleting
the backup:
```sh
git stash apply 'stash@{0}'
git status
```
This restores content but does not guarantee the previous staged/unstaged
split. If that split is important, use `git stash apply --index 'stash@{0}'`
instead of the plain apply; index restoration can fail when the base changed.
Inspect the resulting state before attempting another operation. Do not
blindly apply the same stash twice.
For stash conflicts, edit and stage the resolved files, then validate the
combined result. There is no `stash --continue` or `stash --abort`; do not run
`git merge --continue` for a stash conflict. Keep the backup until the content
and intended staging are correct. If recovery is unclear, preserve the current
files and stash before making further changes; avoid destructive resets.
Once the restored work is verified and no newer stash changed the numbering,
remove only the recorded backup:
```sh
git stash drop 'stash@{0}'
```
### Rebase only private work
You may rebase or amend personal, unshared commits before review. Start with
a clean working tree and create a backup branch before rewriting history:
```sh
git branch backup/quality-format-before-rebase
git fetch upstream
git rebase upstream/dev
```
Use `origin/dev` instead for a canonical clone. Resolve conflicts, stage the
resolved paths, and use `git rebase --continue`; use `git rebase --abort` to
return to the pre-rebase branch state. Revalidate the result. Do not use
`--skip` unless you have verified that the commit is intentionally redundant.
A published personal branch may be rewritten only when nobody else's work
depends on it and affected reviewers have agreed. Fetch and inspect its
current remote history first, preserve a backup, and use `--force-with-lease`
only for that topic branch. A rejected lease means the remote changed: inspect
it instead of retrying with `--force`. Neither option is permitted for `dev`,
`main`, or a shared topic branch under this workflow.
## Recovery and releases
To undo a published change, create a new branch from current `dev` and use
`git revert COMMIT_SHA`, then submit the revert through review. For a merge
commit, inspect its parents and agree on the intended mainline with a
maintainer before using the `-m` option. Reverting creates new history;
resetting a shared branch rewrites it.
To find a lost local commit, inspect `git reflog`, verify the candidate with
`git show COMMIT_SHA`, and preserve it with
`git branch recovery/topic COMMIT_SHA`. Reflogs are local and expire; they
are not a durable backup and do not generally recover uncommitted file edits.
Maintainers choose and review the release revision on `main`, verify the
applicable release evidence, and publish the intended `v*` tag. Such tags
trigger the existing [release workflow](../.github/workflows/release.yml).
Do not move or reuse published release tags. Follow
[Engineering Workflow](engineering.md) for artifacts and release validation;
ordinary contribution pushes should name their topic branch explicitly and
should not publish tags.