Git is a version control system and a powerful tool for tracking the change history of software development projects. This page explains Git operational methods and integration with CI/CD tools.
Git Flow is one of the methodologies for branch management using Git, proposed by Vincent Driessen in 2010. This workflow provides a systematic approach to efficiently advance development while maintaining code quality, especially in large-scale projects where multiple developers work simultaneously.
Git Flow uses multiple branches with specific roles, each representing different stages of the development process. This model enables organized release management, feature development, and bug fixes.
In Git Flow, there are always two main branches:
This branch contains production-ready code. The code in this branch should always be in a deployable state for the production environment. Commits to the master branch are typically made only during new version releases or when applying hotfixes.
This branch reflects the latest state of development. Development work for the next release branches off from this branch, and completed features are merged back into it. When the develop branch is stable and ready for release, a release branch is created to prepare for the release.
Git Flow uses the following three types of supporting branches:
These branches are used for developing new features. They always branch off from the develop branch and are merged back into the develop branch when development is complete.
The naming convention is typically feature/feature-name
.
Creation method: git checkout -b feature/new-feature develop
Merge method: git checkout develop
→ git merge --no-ff feature/new-feature
These branches are for release preparation. They branch off from the develop branch, and when release preparation is complete, they are merged into both master and develop.
Only bug fixes and small changes related to the release are made on this branch; no new features are added.
The naming convention is typically release/version-number
.
Creation method: git checkout -b release/1.0.0 develop
Merge method:
git checkout master
→ git merge --no-ff release/1.0.0
→ git tag -a 1.0.0
git checkout develop
→ git merge --no-ff release/1.0.0
These branches are used for urgent bug fixes discovered in the production environment. They branch off from the master branch,
and after the fix is complete, they are merged into both master and develop.
The naming convention is typically hotfix/version-number
.
Creation method: git checkout -b hotfix/1.0.1 master
Merge method:
git checkout master
→ git merge --no-ff hotfix/1.0.1
→ git tag -a 1.0.1
git checkout develop
→ git merge --no-ff hotfix/1.0.1
There is a command-line tool called "git-flow" for implementing Git Flow. Using this tool makes it easy to perform branch operations according to the Git Flow workflow.
macOS (Homebrew): brew install git-flow-avh
Ubuntu/Debian: apt-get install git-flow
Windows (Git for Windows): Included by default
Repository initialization: git flow init
Start feature development: git flow feature start feature-name
Complete feature development: git flow feature finish feature-name
Start release preparation: git flow release start version-number
Complete release preparation: git flow release finish version-number
Start hotfix: git flow hotfix start version-number
Complete hotfix: git flow hotfix finish version-number
GitHub Flow is a simpler workflow than Git Flow and is based on continuous deployment. It is characterized by a simple flow of creating feature branches from the master branch and merging them back into master through pull requests after development is complete.
GitLab Flow is a workflow positioned between Git Flow and GitHub Flow. It introduces environment branches (production, staging, pre-production, etc.), and is characterized by a gradual merging flow from feature branches to master, and then to environment branches.
Trunk Based Development is a simple workflow where all developers either commit directly to a single branch (trunk/master) or use short-lived feature branches. It is suitable for teams that emphasize continuous integration (CI).
Git Flow is a branch management strategy particularly suited for large-scale projects or projects with clear release cycles. However, it is not suitable for all projects, and it is important to select an appropriate Git workflow based on the size and requirements of your project.
When adopting Git Flow, the key to success is for the entire team to understand and consistently apply its rules and procedures. Additionally, using the git-flow tool can simplify complex branch operations.
CircleCI is a cloud-based platform for implementing continuous integration/continuous delivery (CI/CD). It integrates with Git repositories such as GitHub and Bitbucket, automatically performing builds, tests, and deployments whenever code changes occur.
By using CircleCI, development teams can automate manual testing and deployment tasks, streamlining the software development process. It also enables early detection of issues, allowing for continuous delivery of high-quality code.
CircleCI is a cloud-based service, eliminating the need for infrastructure management. It also offers self-hosted runners, enabling job execution in private environments.
CircleCI easily integrates with major Git repository hosting services such as GitHub and Bitbucket. It automatically executes workflows triggered by events like pushes to repositories or pull requests.
By running tests in parallel, CircleCI reduces build and test times. It also accelerates repetitive processes by caching dependencies and build results.
CircleCI can integrate with many third-party services including Slack, JIRA, AWS, Google Cloud, and Docker. This allows you to integrate development workflows into your existing toolchain.
Using YAML-based configuration files, you can customize build, test, and deployment processes. Complex workflows and conditional executions can also be configured.
1. Access the CircleCI website (https://circleci.com/).
2. Sign up with your GitHub or Bitbucket account.
3. Select the repository you want to integrate and click "Set Up Project".
To use CircleCI, you need to create a .circleci
directory in your project's root directory,
and place a configuration file called config.yml
inside it.
Example of a basic configuration file:
version: 2.1
jobs:
build:
docker:
- image: cimg/node:16.13
steps:
- checkout
- run:
name: "Install dependencies"
command: npm install
- run:
name: "Run tests"
command: npm test
You can set up workflows to run multiple jobs sequentially or in parallel.
version: 2.1
jobs:
build:
docker:
- image: cimg/node:16.13
steps:
- checkout
- run: npm install
- run: npm run build
- persist_to_workspace:
root: .
paths:
- .
test:
docker:
- image: cimg/node:16.13
steps:
- attach_workspace:
at: .
- run: npm test
deploy:
docker:
- image: cimg/node:16.13
steps:
- attach_workspace:
at: .
- run: npm run deploy
workflows:
version: 2
build-test-deploy:
jobs:
- build
- test:
requires:
- build
- deploy:
requires:
- test
filters:
branches:
only: main
A job is a unit of work that executes a series of steps (commands). Each job runs in its own execution environment (Executor).
Steps are individual actions (commands or scripts) that are executed within a job. For example, checking out code, installing dependencies, and running tests are all steps.
Executors define the environment in which jobs are run. CircleCI provides three types of executors:
Workflows define the execution order and conditions for multiple jobs. You can run jobs in parallel or execute certain jobs after other specific jobs have completed.
Orbs are reusable configuration packages. They allow you to easily incorporate common tasks and integrations into your configuration file. For example, orbs are provided for easy integration with services like AWS, Slack, and Docker.
version: 2.1
orbs:
node: circleci/node@4.7
aws-cli: circleci/aws-cli@2.0.3
jobs:
build-and-deploy:
executor: node/default
steps:
- checkout
- node/install-packages
- run: npm run build
- aws-cli/setup
- run: aws s3 sync ./build s3://my-bucket/
Sensitive information (such as API keys and passwords) can be set as environment variables in the CircleCI web interface. Additionally, environment variables that are shared across multiple projects can be managed as "contexts".
By caching the results of time-consuming processes, such as installing dependencies, you can reduce build times.
steps:
- checkout
- restore_cache:
keys:
- v1-dependencies-{{ checksum "package.json" }}
- v1-dependencies-
- run: npm install
- save_cache:
paths:
- node_modules
key: v1-dependencies-{{ checksum "package.json" }}
By distributing tests across multiple containers for parallel execution, you can reduce testing time.
jobs:
test:
parallelism: 4
steps:
- checkout
- run: npm install
- run:
command: |
TESTFILES=$(circleci tests glob "test/**/*.js" | circleci tests split --split-by=timings)
npm test -- $TESTFILES
By adding a manual approval step to a workflow, you can require human approval before executing certain jobs (e.g., deploying to a production environment).
workflows:
version: 2
build-test-deploy:
jobs:
- build
- test:
requires:
- build
- hold:
type: approval
requires:
- test
- deploy:
requires:
- hold
You can configure jobs to run only for specific branches or tags.
For example, you can set up deployments to production to only execute when pushing to the main
branch.
workflows:
version: 2
build-test-deploy:
jobs:
- build
- test:
requires:
- build
- deploy:
requires:
- test
filters:
branches:
only: main
tags:
only: /^v.*/
CircleCI integrates with pull requests on GitHub and Bitbucket, displaying build results in the pull request status. This makes it easier to check test results during code reviews.
Before committing your CircleCI configuration file, it's recommended to validate its syntax using the CircleCI CLI tool.
circleci config validate
You can use the CircleCI CLI tool to run jobs locally and test your configuration.
circleci local execute
You can reduce build times using the following methods:
Sensitive information (API keys, passwords, etc.) should be set as environment variables and not written directly in configuration files. It's also recommended to utilize security-related features such as permission management and audit log review.
CircleCI is a powerful platform for implementing continuous integration/continuous delivery (CI/CD). By integrating Git repositories with CircleCI, you can automatically build, test, and deploy whenever code changes occur, streamlining the software development process.
By defining flexible workflows using YAML-based configuration files and leveraging parallel execution and caching features, you can improve your development team's productivity. CircleCI also integrates with many third-party services, making it easy to incorporate into existing development workflows.
GitHub Actions is a workflow automation tool provided by GitHub. It can automatically execute a series of processes such as building, testing, and deploying, triggered by events that occur in the repository (pushes, pull requests, releases, etc.).
By using GitHub Actions, you can build CI/CD (continuous integration/continuous delivery) pipelines directly within your GitHub repository, eliminating the need for external services. Additionally, you can efficiently construct workflows by reusing numerous actions created by the community.
GitHub Actions is fully integrated with the GitHub platform. It directly connects with repository code, pull requests, issues, and more, allowing you to seamlessly automate development workflows.
GitHub Actions can run workflows on multiple operating systems including Linux, Windows, and macOS. This makes it easier to build and test applications for different platforms.
With GitHub Actions, you can create and share reusable components (actions) for performing specific tasks. The GitHub Marketplace hosts numerous actions created by the community, which you can combine to efficiently build your workflows.
GitHub Actions supports matrix builds, which allow you to run jobs in parallel with multiple configurations (different OS or runtime versions, etc.). This enables efficient compatibility testing across different environments.
In addition to GitHub-provided hosted runners, you can run workflows on your own machines (self-hosted runners). This provides flexibility when you have special hardware requirements or need access to internal networks.
To use GitHub Actions, you create a YAML file (e.g., ci.yml
) in the .github/workflows
directory
of your repository. This file contains the workflow configuration.
Example of a basic workflow file:
name: CI
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Set up Node.js
uses: actions/setup-node@v3
with:
node-version: '16'
- name: Install dependencies
run: npm install
- name: Run tests
run: npm test
GitHub Actions workflows consist of the following key components:
The most common triggers are pushes to specific branches or pull requests. You can also filter to run workflows only for specific branches or paths.
on:
push:
branches: [ main, develop ]
paths:
- 'src/**'
- 'package.json'
pull_request:
branches: [ main ]
You can use cron syntax to run workflows on a regular schedule. This is useful for regular backups or checking for dependency updates.
on:
schedule:
# Run at 3 AM (UTC) every day
- cron: '0 3 * * *'
Using the workflow_dispatch
event, you can manually run workflows
from the GitHub web interface. You can also optionally define input parameters.
on:
workflow_dispatch:
inputs:
environment:
description: 'Deployment environment'
required: true
default: 'staging'
type: choice
options:
- staging
- production
GitHub Actions supports many GitHub events as triggers, including release creation, issue creation/updates, and discussion creation.
on:
release:
types: [published]
issues:
types: [opened, edited]
Each job in a workflow runs in an independent execution environment. By default, jobs run in parallel, but you can define dependencies to run them sequentially.
jobs:
build:
runs-on: ubuntu-latest
steps:
# Build steps...
test:
needs: build
runs-on: ubuntu-latest
steps:
# Test steps...
deploy:
needs: [build, test]
runs-on: ubuntu-latest
steps:
# Deploy steps...
Using a matrix strategy, you can run the same job multiple times with different configurations (such as OS or runtime versions).
jobs:
test:
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest, windows-latest, macos-latest]
node-version: [14.x, 16.x, 18.x]
steps:
- uses: actions/checkout@v3
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v3
with:
node-version: ${{ matrix.node-version }}
- run: npm install
- run: npm test
You can use artifacts to share files between jobs. This is useful when you need to use build artifacts in testing or deployment jobs.
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- run: npm install
- run: npm run build
- uses: actions/upload-artifact@v3
with:
name: build-files
path: dist/
deploy:
needs: build
runs-on: ubuntu-latest
steps:
- uses: actions/download-artifact@v3
with:
name: build-files
path: dist/
- run: ./deploy.sh
Many published actions are registered in the GitHub Marketplace. Using these actions makes it easy to implement common tasks.
Actions are referenced using the uses
keyword:
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: '16'
- uses: actions/cache@v3
with:
path: ~/.npm
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
You can create your own custom actions to meet specific needs. Actions can be implemented as JavaScript or Docker containers.
Example of a JavaScript action (action.yml
):
name: 'Hello World'
description: 'An action that displays a greeting'
inputs:
who-to-greet:
description: 'Who to greet'
required: true
default: 'World'
outputs:
time:
description: 'The time when the greeting was made'
runs:
using: 'node16'
main: 'index.js'
Corresponding JavaScript file (index.js
):
const core = require('@actions/core');
try {
// Get input parameter
const nameToGreet = core.getInput('who-to-greet');
console.log(`Hello ${nameToGreet}!`);
// Set output parameter
const time = new Date().toTimeString();
core.setOutput("time", time);
} catch (error) {
core.setFailed(error.message);
}
You can define environment variables in your workflow and share them between steps.
jobs:
build:
runs-on: ubuntu-latest
env:
NODE_ENV: production
steps:
- uses: actions/checkout@v3
- name: Display environment variables
run: echo "NODE_ENV is $NODE_ENV"
- name: Step-level environment variables
env:
DEBUG: true
run: echo "DEBUG is $DEBUG"
Sensitive information such as API keys and passwords can be stored as GitHub repository secrets and used safely within your workflows.
How to set up secrets:
Using secrets in workflows:
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v1
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: ap-northeast-1
You can use if
conditions to run jobs or steps only when specific conditions are met.
jobs:
deploy-to-production:
if: github.ref == 'refs/heads/main'
runs-on: ubuntu-latest
steps:
# Deploy steps...
notify:
runs-on: ubuntu-latest
steps:
- name: Success notification
if: success()
run: ./notify-success.sh
- name: Failure notification
if: failure()
run: ./notify-failure.sh
GitHub Actions provides many functions and operators that can be used in conditional expressions or for generating values.
steps:
- name: Process based on branch name
if: contains(github.ref, 'feature/')
run: echo "This is a feature branch"
- name: Set environment variable
run: echo "TIMESTAMP=$(date +%s)" >> $GITHUB_ENV
- name: Use environment variable
run: echo "Current timestamp is ${{ env.TIMESTAMP }}"
You can build a complete CI/CD pipeline including build, test, and deployment by combining multiple jobs.
name: CI/CD Pipeline
on:
push:
branches: [ main, develop ]
pull_request:
branches: [ main, develop ]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Set up Node.js
uses: actions/setup-node@v3
with:
node-version: '16'
- name: Install dependencies
run: npm ci
- name: Build
run: npm run build
- name: Upload build artifacts
uses: actions/upload-artifact@v3
with:
name: build-files
path: dist/
test:
needs: build
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Set up Node.js
uses: actions/setup-node@v3
with:
node-version: '16'
- name: Install dependencies
run: npm ci
- name: Run tests
run: npm test
deploy-staging:
if: github.ref == 'refs/heads/develop'
needs: [build, test]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Download build artifacts
uses: actions/download-artifact@v3
with:
name: build-files
path: dist/
- name: Deploy to staging
run: ./deploy-staging.sh
deploy-production:
if: github.ref == 'refs/heads/main'
needs: [build, test]
runs-on: ubuntu-latest
environment: production
steps:
- uses: actions/checkout@v3
- name: Download build artifacts
uses: actions/download-artifact@v3
with:
name: build-files
path: dist/
- name: Deploy to production
run: ./deploy-production.sh
GitHub Actions is a powerful workflow automation tool directly integrated with GitHub repositories. It can automatically execute a series of processes such as building, testing, and deploying, triggered by events like code pushes or pull requests.
By leveraging features such as reusable actions, matrix builds, and self-hosted runners, you can build efficient and flexible CI/CD pipelines. Additionally, you can easily extend your development workflows by using the numerous actions published in the GitHub Marketplace.
By implementing GitHub Actions, development teams can automate manual testing and deployment tasks, enabling faster software releases while improving code quality.
Git Fork is the process of creating a copy of another developer's repository in your own account. By forking, you can make changes to a project freely without affecting the original repository. This is an essential feature for contributing to open-source projects and collaborative development within organizations.
After making changes to a forked repository, you can propose those changes to the original repository by creating a Pull Request (or Merge Request). This allows the project maintainers to review your changes and merge them into the original repository if appropriate.
In Git terminology, "fork" and "clone" are similar but distinct concepts:
git clone
command.In a typical workflow, you first fork a repository and then clone your fork to work on it locally.
Forks are primarily used for the following purposes:
The process of forking a repository on GitHub is very simple:
Once the fork is complete, a copy of the original repository will be created in your account.
The URL of this repository will typically be https://github.com/your-username/repository-name
.
The process for forking a repository on GitLab is similar:
To work with your forked repository locally, first create a clone:
git clone https://github.com/your-username/repository-name.git
cd repository-name
To make it easier to sync with the original repository (upstream repository), it's recommended to add an "upstream" remote:
git remote add upstream https://github.com/original-owner/repository-name.git
To verify that the remotes are set up correctly:
git remote -v
This should display something like:
origin https://github.com/your-username/repository-name.git (fetch)
origin https://github.com/your-username/repository-name.git (push)
upstream https://github.com/original-owner/repository-name.git (fetch)
upstream https://github.com/original-owner/repository-name.git (push)
To incorporate changes from the original repository (upstream repository) into your fork, follow these steps:
# Fetch the latest changes from the upstream repository
git fetch upstream
# Switch to your local main branch
git checkout main
# Merge the changes from the upstream repository into your local main branch
git merge upstream/main
# Push the changes to your fork
git push origin main
This keeps your fork synchronized with the original repository and up to date.
The typical workflow for making changes in a forked repository and proposing them to the original repository is:
git checkout -b feature/new-feature-name
git add .
git commit -m "Description of changes"
git push origin feature/new-feature-name
The steps to create a pull request on GitHub are:
Best practices for creating effective pull requests include:
If additional changes are needed after submitting a pull request, simply commit and push to the same branch:
git add .
git commit -m "Address review feedback"
git push origin feature/new-feature-name
These changes will automatically be added to the existing pull request.
When using a fork over an extended period, it's important to synchronize regularly with the upstream repository. This minimizes conflicts and allows you to incorporate the latest features and bug fixes.
The frequency of synchronization depends on how active the upstream repository is, but it's recommended to always sync before making new changes.
When you've completed your contributions to a project and no longer need the fork, you have several options:
It's also possible to contribute to someone else's fork. This is useful when multiple developers are collaborating to propose a significant change to the original repository.
In this case, you can add their fork as a remote and pull from or push to it:
git remote add collaborator https://github.com/collaborator-username/repository-name.git
git fetch collaborator
git checkout -b feature/collaborative-feature collaborator/feature/collaborative-feature
# Make changes
git push collaborator feature/collaborative-feature
Forks are ideal for trying experimental changes without affecting the original project. For example, you can test new technologies or approaches, or perform large-scale refactoring.
If the experiment is successful, you can propose the changes to the original repository. If it fails, there's no impact on the original project.
Merge conflicts can occur when syncing with the upstream repository or when creating a pull request. This happens when the same part of a file has been changed in different ways.
To resolve merge conflicts:
<<<<<<<
, =======
, >>>>>>>
).git add .
git commit -m "Resolve merge conflicts"
Forks that haven't been synchronized for a long time can fall significantly behind the upstream repository. In this case, you can:
git fetch upstream
git rebase upstream/main
Git Fork is an essential feature for contributing to open-source projects and collaborative development. By using forks, you can contribute to projects even without direct access to the original repository, or start new projects based on existing code.
Effective use of forks involves regular synchronization with the upstream repository, proper branch management, and creating clear pull requests. By following these practices, you can enable smooth collaborative development and effectively contribute to open-source communities and team development.
Forking is not just a technical feature but also a social tool that enables distributed collaborative development. It allows developers from around the world to collaborate beyond geographical constraints and create better software together.