Git in Practice: From Fork to Pull Request

Version control systems let multiple people work on the same project in isolated environments while maintaining a single authoritative source — typically called the “master” branch. Git and GitHub are the most common pairing, though GitLab and Bitbucket offer similar hosting. The workflow below covers the essentials: fetching a project, making changes, and getting those changes merged.

Before starting, you’ll need:

  • A GitHub account
  • Node and NPM installed locally
  • Familiarity with basic terminal commands

Fork and Clone

Forking creates a copy of the repository under your own GitHub account. Navigate to the target repository and click the “Fork” button in the top-right corner. This fork becomes your origin remote.

Next, clone the repository to your local machine. From your terminal, move to the directory where you keep projects — for example, a /github folder inside your user directory — and run:

cd ~/             ## you'll usually start in your root directory, but just in case you don't this will take you there
mkdir github      ## this creates a "github" folder — on OSX it will now be located at users/your-username/github
cd github         ## this command navigates you inside the github folder

Then clone your fork:

clone https://github.com/yourGitHubUsername/liferay.design

You’ll see terminal output as Git downloads the code. Once finished, you have a complete local copy ready for modification.

Install and Run

Change into the project directory — here, cd liferay.design. Most repositories include a README.md in the root with setup instructions. Typically you’ll run npm install to fetch dependencies, then npm run dev to launch a local development server. The terminal output will indicate where the site is running — for this project, open a browser and visit localhost:7777.

Committing Changes

A commit groups a set of related changes — think of it as saving progress at a checkpoint. A good rule: create a commit when you’ve accomplished one discrete task, and the project would still function if that commit were removed. The “Issues” tab on GitHub lists tasks needing attention if you’re looking for starting points.

After modifying files, stage and commit them:

git status                                         ## this will print out a list of files that you've made changes in
git add path/to/folder/or/file.ext                 ## this will add the file or folder to the commit
git commit -m 'Summarize the changes you've made'  ## this command creates a commit and a commit message

For commit messages, follow Chris Beams’s guidance: the subject line should complete the sentence, “If applied, this commit will [your subject].” That keeps messages clear and actionable.

Push and Open a Pull Request

To move your local commits to your GitHub fork, run git push origin.

Your fork’s page on GitHub will now show a banner: “This branch is X commits ahead repo-name:branch,” with options for “Pull request” or “Compare.” Clicking “Pull request” leads to a comparison view, then a “Create pull request” button opens the submission form. Add a title and a concise comment explaining your changes to help maintainers review them. While command-line tools like Node GH and GitHub’s official CLI exist, the web interface is perfectly adequate for this step.

Configuring Remotes

After forking, you have three repository references to manage:

  1. upstream: the original repository you forked from
  2. origin: your fork on GitHub
  3. local: the code on your computer

You have origin and local set up already, but linking upstream keeps you synchronized with the primary source. Without it, your fork drifts from the original project, leading to avoidable merge conflicts when submitting pull requests.

Add the upstream remote:

git remote add upstream https://github.com/liferay-design/liferay.design

Verify your configuration with git remote -v — you should see both remotes listed. To pull in the latest upstream changes when your local branch is clean, run:

git pull upstream master && git reset --hard upstream/master

This resets your local branch to match the upstream state — useful when you haven’t touched the project in a while. GitHub’s documentation on configuring remotes for a fork provides further detail.

HTML And CSS: What They Actually Are

HTML (HyperText Markup Language) does two jobs. Hypertext means the document contains references — hyperlinks — to other documents that readers can immediately access. Markup language means the document is annotated with tags that give structure to the text in a way that is syntactically distinguishable from the content itself. In short, CSS (Cascading Style Sheets) controls what those structured elements look like, with "cascading" being the method browsers use to resolve which rule wins when multiple style sheets conflict.

An HTML document has two main parts:

  • The <head> holds metadata and links to imported stylesheets and scripts — nothing here is displayed by the browser.
  • The <body> contains the content the browser actually renders. The browser layers its own default styles for each tag type under the site's custom styles (referenced from the <head> or inline) to produce the final view.

CSS gets a bad reputation on large sites with inconsistent, undocumented style rules. The solution isn't memorization — as Rachel Andrew put it in her guide How To Learn CSS, "You don't need to commit to memorizing every CSS Property and Value." Focus instead on fundamentals: selectors, inheritance, the box model, and — most importantly — how to debug CSS in the browser developer tools. Syntax details like the background property or exact Flexbox alignment are quick lookups; modern code editors even have built-in autocomplete. A feature like Firefox 70's inactive CSS rules indicator saves hours of head-scratching over why a style never applied.

Why Semantic Markup Pays Off

Semantic code is markup that carries meaning about the content it wraps, not just presentational intent. Learning it early gives you a lot for free:

  1. Default styles: an <h1> gets headline-sized text without extra CSS.
  2. Accessible content: semantic HTML works with screen readers and keyboard navigation out of the box.
  3. SEO benefits: machines parse semantic structure more easily for search engines.
  4. Performance benefits: clean HTML leads to clean CSS and less code overall — the foundation of a high-performing site.

For deeper reading, Heydon Pickering's "Structural Semantics" covers HTML5 sectioning elements in detail.

Core Engineering Principles

Abstraction: Separating Form From Function

At its simplest, abstraction lets you define a value or structure once and reference it by name. Three places it matters most for frontend work:

Tokens

Design tools from Photoshop onward have adopted this concept, and CSS/SASS variables are the same idea. Name a color value — say $blue-00 mapped to #0B5FFF — and use the token everywhere instead of the literal hex. Changing the color updates in one spot. Other systems might map it to #0B36CE, but only the token definition changes.

You can take it a level further with functional tokens. Map $primary-color to $blue-00, and your markup references the function of the color ("primary") rather than a specific hue. Retheming becomes a matter of remapping $primary-color to a new value — markup stays untouched.

Components

Componentization is the next layer of abstraction. What started with symbols in tools like Fireworks and Sketch is now standard in Figma, Framer, Adobe XD, InVision Studio, and Webflow. Instead of bespoke form for every instance, you define a reusable structure that accepts small variations. Nicole Sullivan's media object demonstrates this well: one component rendered in varied ways can compose an entire page, returning both consistent form and flexible function.

DRY And The Rule Of Three

DRY (Don't Repeat Yourself) pushes you toward reusable code. You can't apply it 100% of the time — and arguably shouldn't — but keeping it in mind surfaces opportunities to consolidate repeated work.

A useful corollary is the rule of three: once you've copy-pasted something three times, rewrite it as a reusable component. As with most guidelines, it varies from project to project.

Two Schools of CSS Organization

There is no single correct way to structure CSS, and most teams end up blending methodologies to fit their project or stack. Still, becoming familiar with the main approaches helps you decide which pattern suits a given situation. These methodologies influence more than just your stylesheets — they shape your file organization, tooling, and even the markup itself.

Atomic CSS: Small Classes, Fast Styling

Atomic CSS — sometimes called functional CSS — centers on small, single-purpose classes that each define one visual function. Notable implementations include Atomic CSS, Tachyons, and Tailwind CSS. The main advantage is speed: you can style and theme components quickly without writing custom rules. The tradeoff is that markup can become cluttered fast as utility classes pile up. For a full introduction, see John Polacek’s article on CSS-Tricks.

BEM: A Bridge to Component-Based Thinking

BEM (Block, Element, Modifier) treats the web page as a set of reusable components. Everything reusable is a block; elements are parts that only exist within a block and can’t be used independently; modifiers describe a state or visual variant. This philosophy maps naturally to modern JavaScript frameworks such as Angular, React, and Vue, which also build UIs from components.

“BEM (Block, Element, Modifier) is a component-based approach to web development.”

BEM: Quick Start

The theory is solid, though the naming convention can feel verbose and repetitive — .menu, .menu__item, and so on — with underscores and hyphens multiplying quickly. For a deeper dive, see Inna Belaya’s BEM For Beginners on Smashing Magazine.

What Comes After HTML and CSS

Once you have solid command of the fundamentals, the learning path continues in several directions:

  1. Functional and object-oriented programming — beyond the basics of scripting, these paradigms are worth exploring in depth.
  2. Higher-level languages and frameworks — TypeScript, Ruby, React, and Vue are natural next steps once HTML and CSS are comfortable.
  3. Querying languages and data handling — GraphQL, MySQL, and REST APIs become accessible and add real power to your projects.

Coding Is Not Engineering

Learning to code is far from impossible, and the internet is packed with resources that keep growing. But it’s worth remembering that coding and software engineering are not the same. Copying from Stack Overflow or making something work in CodePen gets you surprisingly far — most engineers have done it. The danger is mistaking that for full engineering understanding. There are dependencies, build processes, and architecture decisions you may not even know exist yet.

That is why the role of designer remains distinct. A designer who codes brings real value: the ability to prototype, verify interactions, and communicate more precisely with engineers. But your primary job is still solving user problems through design patterns and methods — and letting engineers make the engineering calls.