DevToolBoxฟรี
บล็อก

Text Diff Online Guide: อัลกอริทึม, git diff และ Best Practices

14 นาทีในการอ่านโดย DevToolBox

TL;DR

A text diff tool finds the exact differences between two versions of a file or string. This guide covers the three major diff algorithms (Myers, Patience, Histogram), how to read git diff output, terminal tools like diff, colordiff, and delta, programmatic diffing in JavaScript (jsdiff) and Python (difflib), semantic vs line-based diffing, three-way merge and conflict resolution, using diffs in CI/CD for regression detection, and best practices for keeping diffs readable.

Key Takeaways

  • The Myers algorithm (used by Git) finds the shortest edit script in O(n*d) time, making it ideal for most diff scenarios.
  • Patience diff and Histogram diff produce more human-readable output by aligning on unique lines and reducing noisy hunks.
  • Unified diff format (lines prefixed with +, -, and @@ hunk headers) is the standard across Git, patch files, and code review tools.
  • Terminal-based viewers like delta and colordiff dramatically improve the readability of command-line diff output.
  • Three-way merge compares two branches against a common ancestor; understanding its mechanics is essential for resolving Git conflicts correctly.
  • Integrating diff-based checks into CI/CD pipelines catches unintended changes to API contracts, configuration files, and snapshots automatically.

Try our free Text Diff Checker tool to compare two texts instantly.

What Is a Diff and Why It Matters

A diff (short for "difference") is the output of comparing two texts or files and identifying what changed between them. Every line is classified as added, removed, or unchanged. The concept was born on Unix in 1974 with the diff command, and it now underpins every version control system, code review platform, and deployment pipeline in modern software engineering.

Diffs matter because they answer the most fundamental question in collaborative development: "What changed?" During a code review, the diff is the artifact reviewers examine. During debugging, the diff between a working commit and a broken one isolates the root cause. During deployment, the diff between the current and previous release defines the blast radius of a change.

Beyond code, diffs are used to compare configuration files before and after changes, track edits in legal documents and contracts, detect unauthorized modifications to critical system files, and verify that data migrations transformed records correctly. Any workflow that involves versions benefits from diffing.

Try our free Text Diff Checker tool to compare two texts instantly.

Diff Algorithms: Myers, Patience, and Histogram

Not all diffs are computed the same way. The choice of algorithm affects both the speed of computation and the readability of the resulting output. Here are the three most important algorithms you should know:

Myers Diff Algorithm

Published by Eugene Myers in 1986, this is the default algorithm in Git. It models the diff problem as finding the shortest path through an edit graph where horizontal edges represent deletions, vertical edges represent insertions, and diagonal edges represent matches. The algorithm runs in O(n*d) time, where n is the size of the input and d is the number of differences. Because most real-world diffs have far fewer changes than total lines, this is extremely fast in practice.

Myers diff finds the shortest edit script (SES), meaning it produces the minimum number of additions and deletions to transform text A into text B. This is mathematically optimal but sometimes produces output that is hard for humans to read, especially when code has been moved or refactored rather than simply edited in place.

Patience Diff Algorithm

Patience diff (invented by Bram Cohen) takes a different approach. It first identifies lines that appear exactly once in both files -- these "unique common lines" serve as reliable anchors. It then uses the Longest Increasing Subsequence (LIS) of these anchors to establish the alignment, and recurses into the gaps between anchors using a standard LCS algorithm.

The result is output that tends to align on function signatures, class declarations, and other structural markers rather than on accidental matches like blank lines or closing braces. You can enable it in Git with git diff --diff-algorithm=patience or by setting diff.algorithm = patience in your .gitconfig.

Histogram Diff Algorithm

Histogram diff is an optimization of Patience diff that was developed for the JGit project (the Java implementation of Git). It builds a histogram of line occurrences to identify low-frequency lines as anchors, then applies the same recursive strategy as Patience diff. It generally produces results of similar quality to Patience diff but can be faster on certain inputs.

Enable it in Git with git diff --diff-algorithm=histogram. Many developers who find the default Myers output confusing on heavily refactored files switch to either Patience or Histogram as their default algorithm.

Algorithm Comparison

AlgorithmTime ComplexityReadabilityBest For
MyersO(n*d)Good (minimal edits)General use, speed-critical
PatienceO(n*d) + LISExcellent (structural alignment)Code review, refactored files
HistogramO(n*d) + histogramExcellentLarge files, balanced speed/readability

git diff Explained: Unified Format and Side-by-Side

The git diff command is the tool developers interact with most frequently for comparing file versions. Understanding its output format is a core developer skill.

Unified Diff Format

By default, git diff outputs in unified diff format. Here is what each part means:

  • File headers: --- a/src/app.js identifies the original file and +++ b/src/app.js identifies the modified file. The a/ and b/ prefixes are virtual path markers.
  • Hunk headers: A line like @@ -15,7 +15,9 @@ function processData() means the hunk starts at line 15 in the original (showing 7 lines) and at line 15 in the modified version (showing 9 lines). The text after the second @@ is the nearest function or scope name, added by Git for context.
  • Changed lines: Lines beginning with - were removed, lines beginning with + were added, and lines with no prefix are unchanged context lines (3 by default, adjustable with -U<n>).
--- a/src/utils.js
+++ b/src/utils.js
@@ -10,7 +10,9 @@ function processData(input) {
   const cleaned = input.trim();
-  const result = transform(cleaned);
-  return result;
+  const validated = validate(cleaned);
+  const result = transform(validated);
+  return { data: result, status: 'ok' };
 }

 // Context lines above and below the change

Essential git diff Commands

# Compare working directory vs staging area (unstaged changes)
git diff

# Compare staging area vs last commit (staged changes)
git diff --staged

# Compare working directory vs HEAD (all uncommitted changes)
git diff HEAD

# Compare two branches
git diff main..feature-branch

# Compare two specific commits
git diff abc1234 def5678

# Diff a specific file only
git diff -- src/config.ts

# Word-level diff (useful for prose/docs)
git diff --word-diff

# Color-coded word-level diff (no markers)
git diff --color-words

# Show only filenames that changed
git diff --name-only HEAD~5

# Show filenames with status (A/M/D)
git diff --name-status main..feature

# Statistics: insertions/deletions per file
git diff --stat

# Choose diff algorithm
git diff --diff-algorithm=patience
git diff --diff-algorithm=histogram

# Ignore whitespace changes
git diff -w

# Show diff with more context (default is 3 lines)
git diff -U10

# Generate a patch file
git diff > changes.patch

# Apply a patch
git apply changes.patch

Side-by-Side View

Git does not natively produce side-by-side output, but several tools provide this view. The delta pager (discussed below) renders side-by-side diffs in the terminal with syntax highlighting. GitHub and GitLab present side-by-side diffs in their pull request interfaces. You can also use diff --side-by-side (or diff -y) from the GNU coreutils diff command for a basic two-column layout.

Comparing Files in the Terminal: diff, colordiff, delta

While git diff covers version-controlled files, you often need to compare arbitrary files. Here are the essential terminal tools:

The Classic diff Command

Available on every Unix-like system, diff is the original file comparison tool. Key flags include -u (unified output), -r (recursive directory comparison), -q (report only whether files differ), -w (ignore whitespace), and -y (side-by-side output). It is the tool that CI/CD scripts and Makefiles typically invoke for automated comparisons.

# Unified diff (most common)
diff -u original.txt modified.txt

# Side-by-side comparison
diff -y --width=120 file1.txt file2.txt

# Recursive directory comparison
diff -r dir1/ dir2/

# Report only which files differ (no details)
diff -rq dir1/ dir2/

# Ignore all whitespace
diff -u -w file1.txt file2.txt

# Ignore blank lines
diff -u -B file1.txt file2.txt

# Brief: only report if files differ (exit code 0 or 1)
diff -q file1.txt file2.txt

colordiff: Color-Enhanced diff

The colordiff wrapper adds ANSI color codes to the output of diff, making additions, deletions, and context immediately distinguishable. Install it via your package manager (apt install colordiff, brew install colordiff) and use it as a drop-in replacement: colordiff -u file1.txt file2.txt. You can also pipe standard diff output through it: diff -u a.txt b.txt | colordiff.

# Install
brew install colordiff    # macOS
apt install colordiff     # Ubuntu/Debian

# Use as drop-in replacement
colordiff -u original.txt modified.txt

# Pipe standard diff through colordiff
diff -u file1.txt file2.txt | colordiff

delta: A Modern Diff Viewer

The delta pager (git-delta) transforms diff output into a richly formatted display with syntax highlighting, line numbers, side-by-side mode, and navigation. It integrates as a Git pager by adding a few lines to your .gitconfig. Once configured, every git diff, git log -p, and git show command automatically renders through delta.

# Install
brew install git-delta    # macOS
apt install delta         # Ubuntu 22.04+

# Configure as Git pager in ~/.gitconfig
[core]
    pager = delta

[interactive]
    diffFilter = delta --color-only

[delta]
    navigate = true
    side-by-side = true
    line-numbers = true
    syntax-theme = Dracula

# Now every git diff, git log -p, git show
# automatically renders through delta

Diff in JavaScript: The jsdiff Library

The diff npm package (commonly called jsdiff) is the standard library for computing text differences in JavaScript and TypeScript. It powers many web-based diff viewers and is used in testing frameworks for snapshot comparison.

Core Diffing Functions

jsdiff provides several granularity levels: Diff.diffChars() compares character by character, Diff.diffWords() splits on word boundaries, Diff.diffLines() compares line by line, and Diff.diffSentences() operates at sentence level. Each function returns an array of change objects with value, added, and removed properties.

import * as Diff from 'diff';

const oldText = `function greet(name) {
  console.log("Hello, " + name);
  return true;
}`;

const newText = `function greet(name, greeting = "Hello") {
  console.log(greeting + ", " + name + "!");
  return { success: true };
}`;

// Line-by-line diff
const changes = Diff.diffLines(oldText, newText);
changes.forEach(part => {
  const prefix = part.added ? '+' : part.removed ? '-' : ' ';
  part.value.split('\n').filter(Boolean).forEach(line => {
    console.log(prefix + ' ' + line);
  });
});

// Character-level diff
const charChanges = Diff.diffChars('hello world', 'hello there');
// Returns: [{value:'hello '}, {removed:true,value:'world'}, {added:true,value:'there'}]

// Word-level diff
const wordChanges = Diff.diffWords(
  'The quick brown fox',
  'The slow brown fox'
);
// Identifies 'quick' -> 'slow' as the only change

Creating and Applying Patches

Diff.createPatch() generates a unified diff string that can be saved as a .patch file. Diff.applyPatch() takes the original text and a patch string and produces the modified text. This is useful for implementing undo/redo functionality or for transmitting changes efficiently over a network.

import * as Diff from 'diff';

// Create a unified patch
const patch = Diff.createPatch(
  'greeting.js',   // filename
  oldText,          // old content
  newText,          // new content
  'v1',             // old header
  'v2'              // new header
);
console.log(patch);
// Outputs standard unified diff format

// Apply the patch to get the new text
const result = Diff.applyPatch(oldText, patch);
console.log(result === newText); // true

// Structured patch (returns parsed hunk objects)
const structured = Diff.structuredPatch(
  'old.js', 'new.js', oldText, newText, '', ''
);
console.log(structured.hunks);
// [{oldStart:1, oldLines:4, newStart:1, newLines:4, lines:[...]}]

Try our free Text Diff Checker tool to compare two texts instantly.

Diff in Python: The difflib Module

Python ships with difflib in its standard library, providing everything from unified diffs to HTML visual comparison reports. No external packages are needed.

Generating Unified Diffs

difflib.unified_diff() takes two sequences of strings (typically lines from splitlines()) and returns an iterator of diff lines in unified format. Pass fromfile and tofile for file headers, and lineterm="" to avoid double newlines when printing.

import difflib

old = """def greet(name):
    print(f"Hello, {name}")
    return True""".splitlines()

new = """def greet(name, greeting="Hello"):
    print(f"{greeting}, {name}!")
    return {"success": True}""".splitlines()

# Generate unified diff
diff = difflib.unified_diff(
    old, new,
    fromfile='greet_v1.py',
    tofile='greet_v2.py',
    lineterm=''
)
print('\n'.join(diff))

# Output:
# --- greet_v1.py
# +++ greet_v2.py
# @@ -1,3 +1,3 @@
# -def greet(name):
# -    print(f"Hello, {name}")
# -    return True
# +def greet(name, greeting="Hello"):
# +    print(f"{greeting}, {name}!")
# +    return {"success": True}

HTML Visual Diff

difflib.HtmlDiff() generates a complete HTML page with a side-by-side table highlighting differences. This is invaluable for generating diff reports in automated testing or documentation pipelines.

import difflib

old = "Hello World\nFoo Bar\nBaz Qux".splitlines()
new = "Hello World\nFoo Baz\nBaz Qux\nNew Line".splitlines()

# Generate a complete HTML diff report
html_diff = difflib.HtmlDiff()
report = html_diff.make_file(old, new, 'Original', 'Modified')

with open('diff_report.html', 'w') as f:
    f.write(report)
# Opens in browser with side-by-side colored comparison

SequenceMatcher for Similarity

difflib.SequenceMatcher provides a ratio() method that returns a float between 0 and 1 representing the similarity of two sequences. This is useful for fuzzy matching, plagiarism detection, and finding the closest match in a list of strings.

from difflib import SequenceMatcher

a = "the quick brown fox"
b = "the slow brown fox jumps"

matcher = SequenceMatcher(None, a, b)
print(f"Similarity: {matcher.ratio():.2%}")  # ~72%

# Get matching blocks
for block in matcher.get_matching_blocks():
    print(f"a[{block.a}:{block.a+block.size}] == b[{block.b}:{block.b+block.size}]")

# Get opcodes (edit operations)
for op, i1, i2, j1, j2 in matcher.get_opcodes():
    print(f"{op:>8s} a[{i1}:{i2}] -> b[{j1}:{j2}]")
# Output: equal, replace, equal, insert

Semantic Diff vs Line-Based Diff

Traditional diff tools operate on lines of text without understanding the content. A line-based diff treats every line as an atomic unit: if a single character changes on a line, the entire line is marked as modified. This works well for most code but can produce misleading output when formatting changes occur (like re-indenting a block or reflowing a paragraph).

A semantic diff (also called structural diff or AST diff) parses the content into a tree structure (such as an Abstract Syntax Tree for code) and compares the trees rather than the raw text. This means it can distinguish between a meaningful code change and a pure formatting change, detect moved functions or methods even when they change position in the file, and produce diffs that align with the logical structure of the language.

Tools like difftastic, GumTree, and Semantic Diff for VS Code implement this approach. While they are more computationally expensive than line-based diff, they are increasingly popular for code review workflows where understanding intent matters more than seeing raw text changes.

For web-based scenarios, Google's diff-match-patch library offers a character-level diff with semantic cleanup heuristics that group changes into human-meaningful units, even without full AST parsing.

Three-Way Merge and Conflict Resolution

A three-way merge occurs when Git (or any VCS) needs to combine changes from two branches that diverged from a common ancestor. Instead of comparing just two files, it considers three versions: the base (common ancestor), ours (current branch), and theirs (incoming branch).

The merge algorithm works by computing two diffs: base-to-ours and base-to-theirs. If a particular region changed in only one of the two diffs, that change is accepted automatically. If both diffs modify the same region in the same way, the change is also accepted (convergent edits). A conflict occurs only when both diffs modify the same region in different ways.

When a conflict occurs, Git writes conflict markers into the file:

<<<<<<< HEAD (ours - current branch)
const timeout = 5000;
=======
const timeout = 10000;
>>>>>>> feature-branch (theirs - incoming branch)

# With diff3 conflict style (recommended):
# git config merge.conflictstyle diff3
<<<<<<< HEAD
const timeout = 5000;
||||||| merged common ancestor (base)
const timeout = 3000;
=======
const timeout = 10000;
>>>>>>> feature-branch

The developer must then manually choose which version to keep, combine them, or write entirely new code. Merge tools like VS Code, IntelliJ, and vimdiff present three-way diffs visually, with the base version in the center and the two branch versions on either side.

Git also supports the diff3 conflict style (git config merge.conflictstyle diff3) which includes the base version between the markers, making it much easier to understand what the original code looked like before either branch changed it.

Diff in CI/CD: Automated Regression Detection

Diffs are not just for human review -- they are powerful tools for automated quality gates in CI/CD pipelines. Here are common patterns:

  • Snapshot Testing: Frameworks like Jest (JavaScript) and pytest (Python) serialize outputs and compare them against stored snapshots. When the diff is non-empty, the test fails, forcing the developer to either fix the regression or explicitly approve the new snapshot.
  • API Contract Checks: Tools like openapi-diff compare OpenAPI/Swagger specs between the current branch and the base branch. Breaking changes (removed endpoints, changed types) fail the CI build, preventing accidental API breakages.
  • Configuration Drift Detection: Infrastructure-as-Code tools like Terraform produce a "plan" that is essentially a diff of the desired state vs the current state. The CI pipeline can block applies that contain unexpected changes.
  • Binary Artifact Diffing: Tools like diffoscope can compare compiled binaries, Docker images, and archives to detect unintended changes in build outputs, such as undeterministic timestamps or embedded secrets.
  • Bundle Size Monitoring: Build pipelines can diff the size of JavaScript bundles or Docker images between commits and flag regressions that exceed a threshold.
# CI/CD example: fail if API spec changed unexpectedly
# .github/workflows/api-check.yml
name: API Contract Check
on: [pull_request]
jobs:
  diff-check:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0
      - name: Check API spec for breaking changes
        run: |
          git diff origin/main -- openapi.yaml > api-diff.txt
          if [ -s api-diff.txt ]; then
            echo "API spec changed. Review required."
            cat api-diff.txt
            npx openapi-diff origin/main:openapi.yaml openapi.yaml
          fi

# Snapshot test in Jest
test('renders correctly', () => {
  const tree = renderer.create(<Component />).toJSON();
  expect(tree).toMatchSnapshot();
  // If output changes, test fails with a diff
});

# Bundle size check
CURRENT_SIZE=$(stat -f%z dist/bundle.js)
BASE_SIZE=$(git show origin/main:dist/bundle.js | wc -c)
DIFF=$((CURRENT_SIZE - BASE_SIZE))
if [ $DIFF -gt 10240 ]; then
  echo "Bundle size increased by $DIFF bytes (>10KB threshold)"
  exit 1
fi

Best Practices for Readable Diffs

The quality of a diff is not just about the algorithm -- it is heavily influenced by how code is written and committed. Here are practices that produce clean, reviewable diffs:

  1. Make atomic commits: Each commit should contain a single logical change. Mixing a refactoring with a feature addition creates a noisy diff that is difficult to review. If you need to refactor before adding a feature, commit the refactoring separately.
  2. Use consistent formatting: Enforce a formatter (Prettier, Black, gofmt) across the project. When everyone uses the same formatting rules, diffs never contain pure formatting noise. Run the formatter as a pre-commit hook so it is automatic.
  3. Avoid unnecessary whitespace changes: Changing indentation style or adding trailing newlines across many files creates massive diffs that obscure real changes. If a whitespace change is needed, do it in a dedicated commit.
  4. Prefer appending to rewriting: When adding entries to a list, configuration file, or array, add new entries at the end rather than inserting in the middle. This minimizes the context that changes in the diff and avoids merge conflicts with other branches modifying the same list.
  5. Add trailing commas in arrays and objects: In languages that support trailing commas (JavaScript, TypeScript, Python, Rust), always include them. This way, adding a new item to a list only produces a one-line diff instead of a two-line diff that modifies the previous last line.
  6. Write descriptive commit messages: While not part of the diff itself, a good commit message helps reviewers understand the intent of a diff before they read it. This context makes the review process faster and more accurate.
  7. Split large PRs into stacked diffs: A 2000-line diff is overwhelming to review. Break large changes into a series of smaller, sequentially dependent pull requests. Each PR is easier to understand and review, and the overall change is less likely to introduce bugs.
# Example: trailing comma produces cleaner diffs

# WITHOUT trailing comma - 2-line diff to add "grape":
  const fruits = [
    "apple",
    "banana",
-   "cherry"
+   "cherry",
+   "grape"
  ];

# WITH trailing comma - 1-line diff to add "grape":
  const fruits = [
    "apple",
    "banana",
    "cherry",
+   "grape",
  ];

Frequently Asked Questions

What is the best diff algorithm for code review?

For most code review scenarios, the Patience diff algorithm produces the most human-readable output because it aligns on unique structural lines like function signatures and class declarations. You can set it as your Git default with git config --global diff.algorithm patience. The default Myers algorithm is faster and produces mathematically minimal diffs, but its output can be confusing when code has been moved or refactored. Histogram diff is a good middle ground: it is faster than Patience on large files while producing similarly readable results.

How do I compare two text files online without installing anything?

Paste the contents of both files into an online diff checker tool like our free Text Diff Checker. The tool highlights added lines in green, removed lines in red, and unchanged context lines in their default color. All processing happens in your browser, so your data never leaves your device. For large files or frequent comparisons, you may prefer a local tool like VS Code (which has a built-in diff editor) or the command-line diff command.

What is the difference between a two-way diff and a three-way merge?

A two-way diff compares two files directly and shows what changed between them. A three-way merge compares two files against their common ancestor (the base version). This extra context allows the merge tool to automatically resolve non-overlapping changes. Three-way merge is what Git uses when combining branches. A conflict only occurs when both branches modify the same region of the base differently.

How do I make git diff output more readable?

Install the delta pager and set it as your Git pager in .gitconfig. Delta adds syntax highlighting, line numbers, and side-by-side mode to all Git diff output. You can also use git diff --word-diff to see changes at word granularity instead of line granularity, which is especially useful for documentation changes. Another option is git diff --color-words, which highlights changed words inline without markers.

Can I use diff tools in CI/CD pipelines?

Yes, diffs are widely used in CI/CD for regression detection. Common patterns include snapshot testing (Jest, pytest), API contract checking with tools like openapi-diff, configuration drift detection with Terraform plan, and bundle size monitoring. The diff command itself can be used in shell scripts with its exit code: it returns 0 if files are identical and 1 if they differ, making it easy to fail a pipeline step on unexpected changes.

What is a semantic diff and when should I use one?

A semantic diff (or structural diff) parses code into an Abstract Syntax Tree and compares the trees rather than raw text lines. This means it can distinguish real logic changes from formatting changes, and it can detect code that has been moved within a file. Tools like difftastic and GumTree implement semantic diffing. Use a semantic diff when reviewing large refactors, when your team has inconsistent formatting, or when you need to understand the intent of changes rather than just the text-level differences.

How does the Patience diff algorithm differ from Myers?

The Myers algorithm finds the mathematically shortest edit script by exploring an edit graph greedily. It is fast (O(n*d) time) but can produce counterintuitive output when code has been rearranged. Patience diff first identifies lines that are unique in both files and uses them as stable anchors, then fills in the gaps recursively. This tends to produce diffs that align with the logical structure of the code (e.g., matching function headers with function headers) rather than on accidental matches like blank lines or braces.

Conclusion

Understanding diff tools and algorithms is essential for effective code review, debugging, and deployment workflows. From choosing the right algorithm (Myers for speed, Patience for readability) to integrating automated diff checks into CI/CD, the ability to quickly and accurately identify changes between file versions is a core engineering skill. For quick comparisons without any setup, use our online tool. For deep integration into your daily workflow, configure delta as your Git pager and consider switching to Patience or Histogram diff as your default algorithm.

Compare two texts instantly with our free online Text Diff Checker tool.

𝕏 Twitterin LinkedIn
บทความนี้มีประโยชน์ไหม?

อัปเดตข่าวสาร

รับเคล็ดลับการพัฒนาและเครื่องมือใหม่ทุกสัปดาห์

ไม่มีสแปม ยกเลิกได้ตลอดเวลา

ลองเครื่องมือที่เกี่ยวข้อง

±Text Diff Checker{ }JSON Formatter#Hash Generator

บทความที่เกี่ยวข้อง

Diff Checker & เปรียบเทียบข้อความ: คู่มือฉบับสมบูรณ์พร้อมตัวอย่างโค้ด

เครื่องมือ diff checker และเปรียบเทียบข้อความฟรี เรียนรู้วิธีการทำงานของอัลกอริทึม diff พร้อมตัวอย่างโค้ดใน JavaScript, Python และ Bash

Git Commands Cheat Sheet: คำสั่งสำคัญที่นักพัฒนาทุกคนต้องรู้

Cheat sheet คำสั่ง Git ฉบับสมบูรณ์: การตั้งค่า branching merging rebasing stashing และ workflow ขั้นสูง

Git Rebase vs Merge: ใช้อันไหนเมื่อไหร่ (พร้อมตัวอย่างภาพ)

เข้าใจความแตกต่างระหว่าง git rebase และ merge เรียนรู้ว่าควรใช้อันไหนเมื่อไหร่