mirror of
https://github.com/The-Low-Code-Foundation/OpenNoodl.git
synced 2026-01-11 23:02:56 +01:00
Merged Axel changes. Added dev docs for Cline
This commit is contained in:
474
dev-docs/guidelines/CODING-STANDARDS.md
Normal file
474
dev-docs/guidelines/CODING-STANDARDS.md
Normal file
@@ -0,0 +1,474 @@
|
||||
# OpenNoodl Coding Standards
|
||||
|
||||
This document defines the coding style and patterns for OpenNoodl development.
|
||||
|
||||
## TypeScript Standards
|
||||
|
||||
### Type Safety
|
||||
|
||||
```typescript
|
||||
// ✅ DO: Explicit types
|
||||
function processNode(node: NodeGraphNode): ProcessResult {
|
||||
return { success: true, data: node.data };
|
||||
}
|
||||
|
||||
// ❌ DON'T: Any types
|
||||
function processNode(node: any): any {
|
||||
return { success: true, data: node.data };
|
||||
}
|
||||
|
||||
// ❌ DON'T: TSFixme
|
||||
function processNode(node: TSFixme): TSFixme {
|
||||
return { success: true, data: node.data };
|
||||
}
|
||||
```
|
||||
|
||||
### When Type is Truly Unknown
|
||||
|
||||
```typescript
|
||||
// ✅ DO: Use unknown and narrow
|
||||
function handleData(data: unknown): string {
|
||||
if (typeof data === 'string') {
|
||||
return data;
|
||||
}
|
||||
if (typeof data === 'object' && data !== null && 'message' in data) {
|
||||
return String((data as { message: unknown }).message);
|
||||
}
|
||||
return String(data);
|
||||
}
|
||||
|
||||
// ✅ DO: Document why if using any (rare)
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
// Any required here because external library doesn't export types
|
||||
function handleExternalLib(input: any): void {
|
||||
externalLib.process(input);
|
||||
}
|
||||
```
|
||||
|
||||
### Interface Definitions
|
||||
|
||||
```typescript
|
||||
// ✅ DO: Define interfaces for data structures
|
||||
interface NodeConfig {
|
||||
name: string;
|
||||
displayName: string;
|
||||
category: string;
|
||||
inputs: Record<string, InputDefinition>;
|
||||
outputs: Record<string, OutputDefinition>;
|
||||
}
|
||||
|
||||
// ✅ DO: Use type for unions/aliases
|
||||
type NodeColor = 'data' | 'logic' | 'visual' | 'component';
|
||||
|
||||
// ✅ DO: Export types from dedicated files
|
||||
// types.ts
|
||||
export interface MyComponentProps {
|
||||
value: string;
|
||||
onChange: (value: string) => void;
|
||||
}
|
||||
```
|
||||
|
||||
## React Standards
|
||||
|
||||
### Functional Components
|
||||
|
||||
```typescript
|
||||
// ✅ DO: Functional components with typed props
|
||||
interface ButtonProps {
|
||||
label: string;
|
||||
onClick: () => void;
|
||||
disabled?: boolean;
|
||||
}
|
||||
|
||||
export function Button({ label, onClick, disabled = false }: ButtonProps) {
|
||||
return (
|
||||
<button onClick={onClick} disabled={disabled}>
|
||||
{label}
|
||||
</button>
|
||||
);
|
||||
}
|
||||
|
||||
// ❌ DON'T: Class components (unless lifecycle methods required)
|
||||
class Button extends React.Component<ButtonProps> {
|
||||
render() {
|
||||
return <button>{this.props.label}</button>;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Hooks Usage
|
||||
|
||||
```typescript
|
||||
// ✅ DO: Proper hook dependencies
|
||||
const handleChange = useCallback((value: string) => {
|
||||
onChange(value);
|
||||
onValidate?.(value);
|
||||
}, [onChange, onValidate]);
|
||||
|
||||
// ✅ DO: Cleanup in effects
|
||||
useEffect(() => {
|
||||
const handler = (e: Event) => { /* ... */ };
|
||||
window.addEventListener('resize', handler);
|
||||
return () => window.removeEventListener('resize', handler);
|
||||
}, []);
|
||||
|
||||
// ❌ DON'T: Missing dependencies
|
||||
const handleChange = useCallback((value: string) => {
|
||||
onChange(value); // onChange not in deps!
|
||||
}, []);
|
||||
```
|
||||
|
||||
### Component Organization
|
||||
|
||||
```typescript
|
||||
// Component file structure
|
||||
import React, { useState, useCallback, useEffect } from 'react';
|
||||
|
||||
// External imports
|
||||
import classNames from 'classnames';
|
||||
|
||||
// Internal imports
|
||||
import { Icon, IconName } from '@noodl-core-ui/components/common/Icon';
|
||||
import { useModel } from '@noodl-utils/hooks';
|
||||
|
||||
// Relative imports
|
||||
import { ButtonProps } from './types';
|
||||
import { validateInput } from './utils';
|
||||
|
||||
// Styles last
|
||||
import css from './Button.module.scss';
|
||||
|
||||
// Types (if not in separate file)
|
||||
interface LocalState {
|
||||
isHovered: boolean;
|
||||
}
|
||||
|
||||
// Component
|
||||
export function Button({ label, onClick, variant = 'primary' }: ButtonProps) {
|
||||
// Hooks first
|
||||
const [state, setState] = useState<LocalState>({ isHovered: false });
|
||||
const model = useModel(SomeModel.instance);
|
||||
|
||||
// Callbacks
|
||||
const handleClick = useCallback(() => {
|
||||
onClick();
|
||||
}, [onClick]);
|
||||
|
||||
// Effects
|
||||
useEffect(() => {
|
||||
// Setup
|
||||
return () => {
|
||||
// Cleanup
|
||||
};
|
||||
}, []);
|
||||
|
||||
// Render helpers
|
||||
const buttonClass = classNames(css.Button, css[variant]);
|
||||
|
||||
// Render
|
||||
return (
|
||||
<button className={buttonClass} onClick={handleClick}>
|
||||
{label}
|
||||
</button>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
## File Organization
|
||||
|
||||
### Directory Structure
|
||||
|
||||
```
|
||||
feature/
|
||||
├── index.ts # Public exports only
|
||||
├── FeatureName.tsx # Main component
|
||||
├── FeatureName.module.scss
|
||||
├── FeatureName.test.ts
|
||||
├── types.ts # Type definitions
|
||||
├── utils.ts # Helper functions
|
||||
└── hooks.ts # Custom hooks (if any)
|
||||
```
|
||||
|
||||
### Index Files (Barrel Exports)
|
||||
|
||||
```typescript
|
||||
// index.ts - Export only public API
|
||||
export { FeatureName } from './FeatureName';
|
||||
export type { FeatureNameProps } from './types';
|
||||
|
||||
// DON'T export internal utilities
|
||||
```
|
||||
|
||||
### Import Order
|
||||
|
||||
```typescript
|
||||
// 1. React
|
||||
import React, { useState, useEffect } from 'react';
|
||||
|
||||
// 2. External packages (alphabetical)
|
||||
import classNames from 'classnames';
|
||||
import { motion } from 'framer-motion';
|
||||
|
||||
// 3. Internal packages (alphabetical by alias)
|
||||
import { Icon } from '@noodl-core-ui/components/common/Icon';
|
||||
import { NodeGraphModel } from '@noodl-models/nodegraphmodel';
|
||||
import { guid } from '@noodl-utils/utils';
|
||||
|
||||
// 4. Relative imports (parent first, then siblings)
|
||||
import { ParentComponent } from '../ParentComponent';
|
||||
import { SiblingComponent } from './SiblingComponent';
|
||||
import { localHelper } from './utils';
|
||||
|
||||
// 5. Types (if separate import needed)
|
||||
import type { MyComponentProps } from './types';
|
||||
|
||||
// 6. Styles
|
||||
import css from './MyComponent.module.scss';
|
||||
```
|
||||
|
||||
## Documentation Standards
|
||||
|
||||
### JSDoc for Public APIs
|
||||
|
||||
```typescript
|
||||
/**
|
||||
* Processes a node and returns the computed result.
|
||||
*
|
||||
* @param node - The node to process
|
||||
* @param options - Processing options
|
||||
* @returns The computed result with output values
|
||||
*
|
||||
* @example
|
||||
* ```typescript
|
||||
* const result = processNode(myNode, { validate: true });
|
||||
* console.log(result.outputs);
|
||||
* ```
|
||||
*/
|
||||
export function processNode(
|
||||
node: NodeGraphNode,
|
||||
options: ProcessOptions = {}
|
||||
): ProcessResult {
|
||||
// Implementation
|
||||
}
|
||||
```
|
||||
|
||||
### File Headers
|
||||
|
||||
```typescript
|
||||
/**
|
||||
* NodeGraphModel - Manages the structure of a node graph.
|
||||
*
|
||||
* This model handles:
|
||||
* - Node creation and deletion
|
||||
* - Connection management
|
||||
* - Graph traversal
|
||||
*
|
||||
* @module models/NodeGraphModel
|
||||
*/
|
||||
```
|
||||
|
||||
### Inline Comments
|
||||
|
||||
```typescript
|
||||
// ✅ DO: Explain "why", not "what"
|
||||
// We batch updates here to prevent cascading re-renders
|
||||
// when multiple inputs change in the same frame
|
||||
this.scheduleAfterInputsHaveUpdated(() => {
|
||||
this.processAllInputs();
|
||||
});
|
||||
|
||||
// ❌ DON'T: State the obvious
|
||||
// Loop through items
|
||||
for (const item of items) {
|
||||
// Process item
|
||||
process(item);
|
||||
}
|
||||
```
|
||||
|
||||
## Naming Conventions
|
||||
|
||||
### Files
|
||||
|
||||
| Type | Convention | Example |
|
||||
|------|------------|---------|
|
||||
| React Component | PascalCase | `NodePicker.tsx` |
|
||||
| Utility | camelCase | `formatUtils.ts` |
|
||||
| Types | camelCase or PascalCase | `types.ts` or `NodeTypes.ts` |
|
||||
| Test | Match source + `.test` | `NodePicker.test.ts` |
|
||||
| Styles | Match component + `.module` | `NodePicker.module.scss` |
|
||||
|
||||
### Code
|
||||
|
||||
```typescript
|
||||
// Constants: UPPER_SNAKE_CASE
|
||||
const MAX_RETRY_COUNT = 3;
|
||||
const DEFAULT_TIMEOUT_MS = 5000;
|
||||
|
||||
// Functions/Methods: camelCase
|
||||
function processNodeGraph() {}
|
||||
function calculateOffset() {}
|
||||
|
||||
// Classes/Interfaces/Types: PascalCase
|
||||
class NodeGraphModel {}
|
||||
interface ProcessOptions {}
|
||||
type NodeColor = 'data' | 'logic';
|
||||
|
||||
// Private members: underscore prefix
|
||||
class MyClass {
|
||||
private _internalState: State;
|
||||
private _processInternal(): void {}
|
||||
}
|
||||
|
||||
// Boolean variables: is/has/should prefix
|
||||
const isEnabled = true;
|
||||
const hasChildren = node.children.length > 0;
|
||||
const shouldUpdate = isDirty && isVisible;
|
||||
```
|
||||
|
||||
## Error Handling
|
||||
|
||||
```typescript
|
||||
// ✅ DO: Specific error types
|
||||
class NodeNotFoundError extends Error {
|
||||
constructor(nodeId: string) {
|
||||
super(`Node not found: ${nodeId}`);
|
||||
this.name = 'NodeNotFoundError';
|
||||
}
|
||||
}
|
||||
|
||||
// ✅ DO: Handle errors gracefully
|
||||
async function fetchData(): Promise<Result> {
|
||||
try {
|
||||
const response = await api.fetch();
|
||||
return { success: true, data: response };
|
||||
} catch (error) {
|
||||
console.error('Failed to fetch data:', error);
|
||||
return { success: false, error: getErrorMessage(error) };
|
||||
}
|
||||
}
|
||||
|
||||
// ✅ DO: Type-safe error messages
|
||||
function getErrorMessage(error: unknown): string {
|
||||
if (error instanceof Error) return error.message;
|
||||
return String(error);
|
||||
}
|
||||
```
|
||||
|
||||
## Testing Standards
|
||||
|
||||
### Test File Structure
|
||||
|
||||
```typescript
|
||||
import { render, screen, fireEvent } from '@testing-library/react';
|
||||
import { MyComponent } from './MyComponent';
|
||||
|
||||
describe('MyComponent', () => {
|
||||
// Group related tests
|
||||
describe('rendering', () => {
|
||||
it('should render with default props', () => {
|
||||
render(<MyComponent />);
|
||||
expect(screen.getByRole('button')).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
describe('interactions', () => {
|
||||
it('should call onClick when clicked', () => {
|
||||
const onClick = jest.fn();
|
||||
render(<MyComponent onClick={onClick} />);
|
||||
|
||||
fireEvent.click(screen.getByRole('button'));
|
||||
|
||||
expect(onClick).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
### Test Naming
|
||||
|
||||
```typescript
|
||||
// ✅ DO: Descriptive test names
|
||||
it('should display error message when validation fails', () => {});
|
||||
it('should disable submit button while loading', () => {});
|
||||
|
||||
// ❌ DON'T: Vague names
|
||||
it('works', () => {});
|
||||
it('test 1', () => {});
|
||||
```
|
||||
|
||||
## Git Commit Messages
|
||||
|
||||
### Format
|
||||
|
||||
```
|
||||
type(scope): description
|
||||
|
||||
[optional body]
|
||||
|
||||
[optional footer]
|
||||
```
|
||||
|
||||
### Types
|
||||
|
||||
- `feat`: New feature
|
||||
- `fix`: Bug fix
|
||||
- `refactor`: Code change that neither fixes bug nor adds feature
|
||||
- `docs`: Documentation only
|
||||
- `test`: Adding or updating tests
|
||||
- `chore`: Build process or auxiliary tool changes
|
||||
|
||||
### Examples
|
||||
|
||||
```
|
||||
feat(editor): add breakpoint support to connections
|
||||
|
||||
fix(runtime): resolve memory leak in collection listener
|
||||
|
||||
refactor(property-panel): convert to functional component
|
||||
|
||||
docs(readme): update installation instructions
|
||||
|
||||
test(nodes): add unit tests for REST node
|
||||
```
|
||||
|
||||
## Performance Guidelines
|
||||
|
||||
### React Performance
|
||||
|
||||
```typescript
|
||||
// ✅ DO: Memoize expensive computations
|
||||
const sortedItems = useMemo(() => {
|
||||
return items.sort((a, b) => a.name.localeCompare(b.name));
|
||||
}, [items]);
|
||||
|
||||
// ✅ DO: Memoize callbacks passed to children
|
||||
const handleChange = useCallback((value: string) => {
|
||||
onChange(value);
|
||||
}, [onChange]);
|
||||
|
||||
// ✅ DO: Use React.memo for pure components
|
||||
export const ListItem = React.memo(function ListItem({ item }: Props) {
|
||||
return <div>{item.name}</div>;
|
||||
});
|
||||
```
|
||||
|
||||
### General Performance
|
||||
|
||||
```typescript
|
||||
// ✅ DO: Batch DOM operations
|
||||
function updateNodes(nodes: Node[]) {
|
||||
// Collect all changes first
|
||||
const changes = nodes.map(calculateChange);
|
||||
|
||||
// Apply in single batch
|
||||
requestAnimationFrame(() => {
|
||||
changes.forEach(applyChange);
|
||||
});
|
||||
}
|
||||
|
||||
// ✅ DO: Debounce frequent events
|
||||
const debouncedSearch = useMemo(
|
||||
() => debounce((query: string) => performSearch(query), 300),
|
||||
[]
|
||||
);
|
||||
```
|
||||
332
dev-docs/guidelines/GIT-WORKFLOW.md
Normal file
332
dev-docs/guidelines/GIT-WORKFLOW.md
Normal file
@@ -0,0 +1,332 @@
|
||||
# Git Workflow Guide
|
||||
|
||||
How to manage branches, commits, and pull requests for OpenNoodl development.
|
||||
|
||||
## Branch Naming
|
||||
|
||||
### Format
|
||||
|
||||
```
|
||||
type/id-short-description
|
||||
```
|
||||
|
||||
### Types
|
||||
|
||||
| Type | Use For | Example |
|
||||
|------|---------|---------|
|
||||
| `task` | Task documentation work | `task/001-dependency-updates` |
|
||||
| `feature` | New features | `feature/vercel-deployment` |
|
||||
| `fix` | Bug fixes | `fix/page-router-scroll` |
|
||||
| `refactor` | Code improvements | `refactor/property-panel-hooks` |
|
||||
| `docs` | Documentation only | `docs/api-reference` |
|
||||
| `test` | Test additions | `test/rest-node-coverage` |
|
||||
|
||||
### Examples
|
||||
|
||||
```bash
|
||||
# Task branches (from dev-docs)
|
||||
git checkout -b task/001-dependency-updates
|
||||
git checkout -b task/002-typescript-cleanup
|
||||
|
||||
# Feature branches
|
||||
git checkout -b feature/add-oauth-support
|
||||
git checkout -b feature/multi-project-windows
|
||||
|
||||
# Fix branches
|
||||
git checkout -b fix/nested-router-scroll
|
||||
git checkout -b fix/array-change-tracking
|
||||
|
||||
# Refactor branches
|
||||
git checkout -b refactor/remove-class-components
|
||||
git checkout -b refactor/data-node-architecture
|
||||
```
|
||||
|
||||
## Commit Messages
|
||||
|
||||
### Format
|
||||
|
||||
```
|
||||
type(scope): short description
|
||||
|
||||
[optional longer description]
|
||||
|
||||
[optional footer with references]
|
||||
```
|
||||
|
||||
### Types
|
||||
|
||||
- `feat` - New feature
|
||||
- `fix` - Bug fix
|
||||
- `refactor` - Code restructuring (no behavior change)
|
||||
- `docs` - Documentation changes
|
||||
- `test` - Test additions/changes
|
||||
- `chore` - Build/tooling changes
|
||||
- `style` - Formatting (no code change)
|
||||
- `perf` - Performance improvement
|
||||
|
||||
### Scopes
|
||||
|
||||
Use the affected area:
|
||||
|
||||
- `editor` - Main editor code
|
||||
- `runtime` - Runtime engine
|
||||
- `viewer` - Viewer/preview
|
||||
- `ui` - Core UI components
|
||||
- `build` - Build system
|
||||
- `deps` - Dependencies
|
||||
|
||||
### Examples
|
||||
|
||||
```bash
|
||||
# Features
|
||||
git commit -m "feat(editor): add connection breakpoints"
|
||||
git commit -m "feat(runtime): implement retry logic for REST node"
|
||||
|
||||
# Fixes
|
||||
git commit -m "fix(viewer): resolve scroll jumping in nested routers"
|
||||
git commit -m "fix(editor): prevent crash when deleting connected node"
|
||||
|
||||
# Refactoring
|
||||
git commit -m "refactor(ui): convert PropertyPanel to functional component"
|
||||
git commit -m "refactor(runtime): simplify collection change tracking"
|
||||
|
||||
# Docs
|
||||
git commit -m "docs(readme): update installation instructions"
|
||||
git commit -m "docs(api): add JSDoc to public methods"
|
||||
|
||||
# Tests
|
||||
git commit -m "test(runtime): add unit tests for REST node"
|
||||
git commit -m "test(editor): add integration tests for import flow"
|
||||
|
||||
# Chores
|
||||
git commit -m "chore(deps): update webpack to 5.101.3"
|
||||
git commit -m "chore(build): enable source maps in development"
|
||||
```
|
||||
|
||||
### Multi-line Commits
|
||||
|
||||
For complex changes:
|
||||
|
||||
```bash
|
||||
git commit -m "feat(editor): add AI-powered node suggestions
|
||||
|
||||
- Integrate with OpenAI API for code analysis
|
||||
- Add suggestion UI in node picker
|
||||
- Cache suggestions for performance
|
||||
|
||||
Closes #123"
|
||||
```
|
||||
|
||||
## Workflow
|
||||
|
||||
### Starting Work
|
||||
|
||||
```bash
|
||||
# 1. Ensure main is up to date
|
||||
git checkout main
|
||||
git pull origin main
|
||||
|
||||
# 2. Create your branch
|
||||
git checkout -b task/001-dependency-updates
|
||||
|
||||
# 3. Make your changes...
|
||||
|
||||
# 4. Stage and commit frequently
|
||||
git add -A
|
||||
git commit -m "feat(deps): update React to v19"
|
||||
```
|
||||
|
||||
### During Development
|
||||
|
||||
```bash
|
||||
# Check status often
|
||||
git status
|
||||
|
||||
# View your changes
|
||||
git diff
|
||||
|
||||
# Stage specific files
|
||||
git add packages/noodl-editor/package.json
|
||||
|
||||
# Commit logical chunks
|
||||
git commit -m "fix(deps): resolve peer dependency conflicts"
|
||||
|
||||
# Push to remote (first time)
|
||||
git push -u origin task/001-dependency-updates
|
||||
|
||||
# Push subsequent commits
|
||||
git push
|
||||
```
|
||||
|
||||
### Keeping Up to Date
|
||||
|
||||
```bash
|
||||
# If main has changed, rebase your work
|
||||
git fetch origin
|
||||
git rebase origin/main
|
||||
|
||||
# Resolve any conflicts, then continue
|
||||
git add .
|
||||
git rebase --continue
|
||||
|
||||
# Force push after rebase (your branch only!)
|
||||
git push --force-with-lease
|
||||
```
|
||||
|
||||
### Creating Pull Request
|
||||
|
||||
1. Push your branch to remote
|
||||
2. Go to GitHub repository
|
||||
3. Click "New Pull Request"
|
||||
4. Select your branch
|
||||
5. Fill in the template:
|
||||
|
||||
```markdown
|
||||
## Summary
|
||||
Brief description of changes
|
||||
|
||||
## Task Reference
|
||||
TASK-001: Dependency Updates
|
||||
|
||||
## Changes Made
|
||||
- Updated React to v19
|
||||
- Fixed peer dependency conflicts
|
||||
- Migrated to createRoot API
|
||||
|
||||
## Testing
|
||||
- [ ] All existing tests pass
|
||||
- [ ] Manual testing completed
|
||||
- [ ] New tests added (if applicable)
|
||||
|
||||
## Checklist
|
||||
- [ ] Code follows style guidelines
|
||||
- [ ] Documentation updated
|
||||
- [ ] CHANGELOG.md updated
|
||||
- [ ] No console.log statements
|
||||
```
|
||||
|
||||
### After PR Merged
|
||||
|
||||
```bash
|
||||
# Switch to main
|
||||
git checkout main
|
||||
|
||||
# Pull the merged changes
|
||||
git pull origin main
|
||||
|
||||
# Delete your local branch
|
||||
git branch -d task/001-dependency-updates
|
||||
|
||||
# Delete remote branch (if not auto-deleted)
|
||||
git push origin --delete task/001-dependency-updates
|
||||
```
|
||||
|
||||
## Common Scenarios
|
||||
|
||||
### Oops, Wrong Branch
|
||||
|
||||
```bash
|
||||
# Stash your changes
|
||||
git stash
|
||||
|
||||
# Switch to correct branch
|
||||
git checkout correct-branch
|
||||
|
||||
# Apply your changes
|
||||
git stash pop
|
||||
```
|
||||
|
||||
### Need to Undo Last Commit
|
||||
|
||||
```bash
|
||||
# Undo commit but keep changes
|
||||
git reset --soft HEAD~1
|
||||
|
||||
# Undo commit and discard changes
|
||||
git reset --hard HEAD~1
|
||||
```
|
||||
|
||||
### Need to Update Commit Message
|
||||
|
||||
```bash
|
||||
# Most recent commit
|
||||
git commit --amend -m "new message"
|
||||
|
||||
# Older commit (interactive rebase)
|
||||
git rebase -i HEAD~3
|
||||
# Change 'pick' to 'reword' for the commit
|
||||
```
|
||||
|
||||
### Accidentally Committed to Main
|
||||
|
||||
```bash
|
||||
# Create a branch with your commits
|
||||
git branch my-feature
|
||||
|
||||
# Reset main to origin
|
||||
git reset --hard origin/main
|
||||
|
||||
# Switch to your feature branch
|
||||
git checkout my-feature
|
||||
```
|
||||
|
||||
### Merge Conflicts
|
||||
|
||||
```bash
|
||||
# During rebase or merge, if conflicts occur:
|
||||
|
||||
# 1. Open conflicted files and resolve
|
||||
# Look for <<<<<<< ======= >>>>>>> markers
|
||||
|
||||
# 2. Stage resolved files
|
||||
git add resolved-file.ts
|
||||
|
||||
# 3. Continue the rebase/merge
|
||||
git rebase --continue
|
||||
# or
|
||||
git merge --continue
|
||||
```
|
||||
|
||||
## Branch Protection
|
||||
|
||||
The `main` branch has these protections:
|
||||
|
||||
- Requires pull request
|
||||
- Requires passing CI checks
|
||||
- Requires up-to-date branch
|
||||
- No force pushes allowed
|
||||
|
||||
## Tips
|
||||
|
||||
### Useful Aliases
|
||||
|
||||
Add to your `~/.gitconfig`:
|
||||
|
||||
```ini
|
||||
[alias]
|
||||
st = status
|
||||
co = checkout
|
||||
br = branch
|
||||
ci = commit
|
||||
lg = log --oneline --graph --all
|
||||
unstage = reset HEAD --
|
||||
last = log -1 HEAD
|
||||
branches = branch -a
|
||||
```
|
||||
|
||||
### Before Every PR
|
||||
|
||||
1. Run tests: `npm run test:editor`
|
||||
2. Run type check: `npx tsc --noEmit`
|
||||
3. Run linter: `npx eslint packages/ --fix`
|
||||
4. Review your diff: `git diff main`
|
||||
5. Check commit history: `git log --oneline main..HEAD`
|
||||
|
||||
### Good Commit Hygiene
|
||||
|
||||
- Commit early and often
|
||||
- Each commit should be atomic (one logical change)
|
||||
- Commits should compile and pass tests
|
||||
- Write meaningful commit messages
|
||||
- Don't commit generated files
|
||||
- Don't commit debug code
|
||||
Reference in New Issue
Block a user