Skip to content

commit Git Command Guide

The git commit command records changes to the repository by creating a new commit object that captures the current state of the index (staging area) along with a descriptive commit message. It serves as the fundamental operation for saving work and creating version history.

Terminal window
git commit [-a | --interactive | --patch] [-s] [-v] [-u<mode>] [--amend]
[--dry-run] [(-c | -C | --squash) <commit> | --fixup [(amend|reword):]<commit>)]
[-F <file> | -m <msg>] [--reset-author] [--allow-empty]
[--allow-empty-message] [--no-verify] [-e] [--author=<author>]
[--date=<date>] [--cleanup=<mode>] [--status | --no-status]
[-S[<keyid>]] [--no-gpg-sign] [--] [<pathspec>...]
OptionDescription
-m <msg>, --message=<msg>Use given message as commit message
-F <file>, --file=<file>Read commit message from file
-C <commit>, --reuse-message=<commit>Reuse message from specified commit
-c <commit>, --reedit-message=<commit>Reuse and edit message from commit
--squash=<commit>Create squash commit message
--fixup=<commit>Create fixup commit message
OptionDescription
-a, --allStage all modified/deleted files before commit
--interactiveInteractively stage changes for commit
--patchInteractively choose hunks to commit
--onlyCommit only specified files (ignore staged changes)
OptionDescription
--amendAmend previous commit instead of creating new one
--reset-authorReset author information when amending
--allow-emptyAllow empty commits with no changes
--allow-empty-messageAllow commits with empty messages
OptionDescription
-v, --verboseShow diff of changes in commit
--dry-runShow what would be committed without committing
--shortShow short status when doing dry run
--porcelainMachine-readable output format
-q, --quietSuppress summary message
--no-statusDon’t include status in commit message template
OptionDescription
-S[<keyid>], --gpg-sign[=<keyid>]GPG-sign the commit
--no-gpg-signDon’t GPG-sign the commit
-s, --signoffAdd Signed-off-by trailer
--no-signoffDon’t add Signed-off-by trailer
OptionDescription
--author=<author>Override commit author
--date=<date>Override author date
--cleanup=<mode>How to clean up commit message
--no-verifySkip pre-commit hooks
-e, --editForce edit of commit message
--pathspec-from-file=<file>Read pathspecs from file
--pathspec-file-nulUse NUL as path separator
ParameterDescription
<pathspec>Limit commit to specific files
Git Commit Object:
├── Tree: Snapshot of files at commit time
├── Parent(s): Reference(s) to previous commit(s)
├── Author: Who wrote the code (name, email, timestamp)
├── Committer: Who created the commit (name, email, timestamp)
├── Message: Description of changes
└── Signature: Optional GPG signature
Commit Creation Process:
1. Validate staged changes exist
2. Create tree object from index
3. Generate commit object with metadata
4. Update current branch reference
5. Run post-commit hooks
Commit Categories:
├── Regular Commits: Normal commits with changes
├── Merge Commits: Commits with multiple parents
├── Empty Commits: Commits with no changes (--allow-empty)
├── Signed Commits: GPG-signed for verification
├── Fixup Commits: Auto-squashed commits (--fixup)
└── Squash Commits: Combined commits (--squash)
Effective Commit Messages:
├── Subject: Brief, imperative mood (<50 chars)
├── Body: Detailed explanation (optional)
├── Footer: Issue references, co-authors
├── Format: Conventional commits (feat:, fix:, docs:)
├── Clarity: Explain what and why, not how
Example Format:
feat: add user authentication system
- Implement JWT token validation
- Add password hashing with bcrypt
- Create user registration endpoint
Closes #123
Terminal window
# Commit staged changes with message
git commit -m "Add user authentication feature"
# Commit with detailed message
git commit -m "Fix database connection timeout
- Increase connection pool size
- Add retry logic for failed connections
- Update error handling"
# Commit all modified files
git commit -a -m "Update documentation"
# Commit specific files only
git commit file1.txt file2.py -m "Fix critical bug"
Terminal window
# Interactively stage and commit
git commit --interactive
# Patch mode for selective hunk committing
git commit --patch
# Verbose commit with diff review
git commit -v
Terminal window
# Amend last commit message
git commit --amend -m "Updated commit message"
# Amend last commit with new changes
git add new-file.txt
git commit --amend --no-edit
# Change author information
git commit --amend --reset-author --no-edit
# Amend with new author
git commit --amend --author="New Author <new@example.com>"
Terminal window
# GPG sign commit
git commit -S -m "Security fix"
# Sign with specific key
git commit -S<keyid> -m "Important change"
# Add signoff trailer
git commit -s -m "Contributed change"
# Configure automatic signing
git config commit.gpgsign true
git config user.signingkey <keyid>
Terminal window
# Allow empty commit
git commit --allow-empty -m "Release version 1.0.0"
# Create annotated tag commit
git commit --allow-empty -m "Tag: v1.0.0"
# Fixup commit for later squashing
git commit --fixup HEAD~2
# Squash commit for later merging
git commit --squash HEAD~3
Terminal window
# Commit from file message
echo "Automated commit" > commit-msg.txt
git commit -F commit-msg.txt
# Batch commit with pathspecs
git commit --pathspec-from-file=files-to-commit.txt
# Automated commits in scripts
if git diff --quiet; then
echo "No changes to commit"
else
git commit -a -m "Automated: $(date)"
fi
Terminal window
# Use commit message template
git config commit.template ~/.git-commit-template
# Template file content:
# [type]: [description]
#
# [body]
#
# [footer]
# Commit with template
git commit # Opens editor with template
Terminal window
# Configure commit behavior
git config commit.verbose true # Always show diff
git config commit.cleanup strip # Clean whitespace
git config commit.gpgsign true # Auto-sign commits
git config commit.status true # Show status in editor
# Configure commit message template
git config commit.template ~/.git-commit-template
# Configure hooks
git config core.hooksPath ~/.git-hooks # Custom hooks location
Terminal window
# Always review before committing
git status # Check staged changes
git diff --cached # Review changes
git diff --check # Check whitespace issues
# Use meaningful commit messages
git commit -m "feat: add user login functionality
- Implement OAuth2 authentication
- Add password reset feature
- Create user session management
Fixes #456"
# Commit frequently but logically
git add feature-file.py
git commit -m "feat: implement core algorithm"
git add tests/
git commit -m "test: add comprehensive test suite"
Terminal window
# Undo last commit (keep changes staged)
git reset --soft HEAD~1
# Undo last commit (keep changes unstaged)
git reset HEAD~1
# Undo last commit (discard changes)
git reset --hard HEAD~1
# Amend commit without changing message
git commit --amend --no-edit
# Fix commit author
git commit --amend --reset-author --no-edit
#!/bin/bash
# Feature branch commit workflow
feature_commit() {
local feature_name="$1"
# Ensure on feature branch
current_branch=$(git rev-parse --abbrev-ref HEAD)
if [[ "$current_branch" != "feature/$feature_name" ]]; then
echo "Not on feature branch"
return 1
fi
# Stage all changes
git add --all
# Check for issues
if ! git diff --cached --quiet; then
# Commit with conventional format
git commit -m "feat: implement $feature_name
- Add core functionality
- Include tests
- Update documentation
Refs: #$feature_name"
else
echo "No changes to commit"
fi
}
feature_commit "user-dashboard"
Terminal window
# Automated commits in CI/CD
ci_commit() {
echo "CI/CD automated commit"
# Stage all changes
git add --all
# Configure git for CI
git config user.name "CI Bot"
git config user.email "ci@company.com"
# Create automated commit
if git diff --cached --quiet; then
echo "No changes to commit"
else
git commit -m "ci: automated commit $(date +%Y%m%d-%H%M%S)
Build: $BUILD_NUMBER
Branch: $BRANCH_NAME
Trigger: $COMMIT_MESSAGE"
fi
}
ci_commit
Terminal window
# Prepare commits for code review
review_commit() {
echo "Preparing commits for code review"
# Ensure clean working tree
if ! git diff --quiet || ! git diff --cached --quiet; then
echo "Working tree not clean. Commit or stash changes first."
return 1
fi
# Create fixup commits for review feedback
echo "Creating fixup commits for review comments..."
# Example: Fix review comment about error handling
git commit --fixup HEAD~2 -m "fixup: improve error handling"
# Example: Add missing tests
git add test-file.py
git commit -m "test: add missing test cases"
echo "Review preparation complete"
}
review_commit
Terminal window
# Fix commit message
git commit --amend -m "Corrected commit message"
# Edit commit message in editor
git commit --amend
# Reuse message from another commit
git commit --reuse-message=HEAD~2
# Clean up messy commit message
git commit --cleanup=strip
Terminal window
# Commit fails - check staged changes
git status
# Nothing staged - stage changes first
git add file.txt
git commit -m "Add file"
# Too many changes - commit in parts
git add --patch
git commit -m "Partial commit"
Terminal window
# Skip hooks for urgent commits
git commit --no-verify -m "Urgent fix"
# Debug hook issues
git config core.hooksPath /dev/null # Temporarily disable
git commit -m "Test commit"
# Check hook permissions
ls -la .git/hooks/pre-commit
chmod +x .git/hooks/pre-commit
Terminal window
# Fix author information
git commit --amend --author="Correct Name <correct@email.com>"
# Override commit date
git commit --date="2023-01-01 12:00:00" -m "Backdated commit"
# Reset author to current user
git commit --amend --reset-author --no-edit
Terminal window
# Commit after resolving conflicts
git add resolved-file.txt
git commit -m "Resolve merge conflicts
- Fixed conflicts in file.txt
- Updated merge strategy
- Verified functionality"
# Empty merge commit
git commit --allow-empty -m "Merge branch 'feature'"
Terminal window
# Split large commits
git reset HEAD~1 # Uncommit but keep changes
git add --patch # Stage in parts
git commit -m "Part 1 of large change"
git commit -a -m "Part 2 of large change"
# Check commit size
git show --stat HEAD
Terminal window
# Handle encoding problems
export LANG=en_US.UTF-8
git commit -m "Message with special chars: àáâãäå"
# Fix encoding in existing commit
git commit --amend --no-edit # Re-commit with correct encoding
Terminal window
# Commit in detached HEAD state
git commit -m "Changes in detached HEAD"
# Create branch from detached HEAD
git checkout -b temp-branch
git checkout main
git merge temp-branch
# Discard detached HEAD commits
git checkout main # Returns to branch
#!/bin/bash
# Conventional commits implementation
conventional_commit() {
local type="$1"
local scope="$2"
local description="$3"
# Validate commit type
valid_types=("feat" "fix" "docs" "style" "refactor" "test" "chore" "perf" "ci" "build" "revert")
if [[ ! " ${valid_types[@]} " =~ " ${type} " ]]; then
echo "Invalid commit type: $type"
echo "Valid types: ${valid_types[*]}"
return 1
fi
# Format commit message
if [ -n "$scope" ]; then
message="$type($scope): $description"
else
message="$type: $description"
fi
# Add breaking change indicator if needed
if [[ "$description" == *"BREAKING CHANGE"* ]]; then
message="$message
BREAKING CHANGE: ${description#*BREAKING CHANGE: }"
fi
# Commit with formatted message
git commit -m "$message"
echo "Committed: $message"
}
# Usage examples
conventional_commit "feat" "auth" "add JWT token validation"
conventional_commit "fix" "" "resolve memory leak in cache"
conventional_commit "docs" "api" "update endpoint documentation"
Terminal window
# Release commit automation
release_commit() {
local version="$1"
local changes="$2"
echo "Creating release commit for version $version"
# Ensure clean working tree
if ! git diff --quiet --cached; then
echo "Staged changes exist. Commit or reset first."
return 1
fi
# Create release commit
git commit --allow-empty -m "chore: release version $version
Release Notes:
$changes
---
Generated by release script
Version: $version
Date: $(date -u +%Y-%m-%dT%H:%M:%SZ)"
# Tag the release
git tag -a "v$version" -m "Release version $version
$changes"
echo "Release $version committed and tagged"
}
release_commit "2.1.0" "- Added new API endpoints
- Fixed authentication bug
- Improved performance"
Terminal window
# Generate changelog from commits
generate_changelog() {
local since_tag="$1"
local output_file="${2:-CHANGELOG.md}"
echo "# Changelog" > "$output_file"
echo "" >> "$output_file"
# Get commits since tag
git log --pretty=format:"* %s (%h)" "$since_tag..HEAD" >> "$output_file"
echo "" >> "$output_file"
echo "Generated from commits since $since_tag" >> "$output_file"
echo "Changelog generated: $output_file"
}
generate_changelog "v1.0.0"
Terminal window
# Lint commit messages
lint_commit_message() {
local message="$1"
# Check length
if [ ${#message} -gt 72 ]; then
echo "Warning: Subject line too long (>72 chars)"
fi
# Check format
if [[ ! "$message" =~ ^(feat|fix|docs|style|refactor|test|chore|perf|ci|build|revert)(\(.+\))?: ]]; then
echo "Warning: Message doesn't follow conventional format"
fi
# Check for empty message
if [ -z "$message" ]; then
echo "Error: Empty commit message"
return 1
fi
echo "Commit message validation passed"
}
# Pre-commit hook integration
cat > .git/hooks/commit-msg << 'EOF'
#!/bin/bash
lint_commit_message "$(cat $1)"
EOF
chmod +x .git/hooks/commit-msg
Terminal window
# Bulk commit operations
bulk_commit() {
local operation="$1"
case "$operation" in
"squash")
# Squash last N commits
local count="$2"
git reset --soft HEAD~"$count"
git commit -m "Squash last $count commits"
;;
"fixup")
# Create fixup commits for multiple commits
local base_commit="$2"
shift 2
local commits_to_fix=("$@")
for commit in "${commits_to_fix[@]}"; do
git commit --fixup "$commit"
done
# Auto-squash
git rebase -i --autosquash "$base_commit"
;;
"reorder")
# Reorder commits interactively
git rebase -i HEAD~10
;;
esac
}
bulk_commit "squash" 3
bulk_commit "fixup" "main" "abc123" "def456"
Terminal window
# Monitor commit health
commit_health_check() {
echo "=== Commit Health Report ==="
# Check recent commits
echo "Recent commits:"
git log --oneline -10
# Check for large commits
echo "Potentially large commits:"
git rev-list --objects HEAD | \
git cat-file --batch-check='%(objecttype) %(objectname) %(objectsize) %(rest)' | \
awk '/^blob/ {print substr($0, 6)}' | \
sort -k2nr | \
head -10 | \
while read -r hash size path; do
if [ "$size" -gt 1048576 ]; then # 1MB
echo "Large file: $path ($size bytes)"
fi
done
# Check commit message quality
echo "Commit message analysis:"
git log --oneline -20 | while read -r line; do
commit_msg=$(echo "$line" | cut -d' ' -f2-)
if [ ${#commit_msg} -lt 10 ]; then
echo "Short message: $commit_msg"
fi
done
# Check for signed commits
signed_count=$(git log --show-signature -20 | grep -c "gpg:")
echo "Signed commits in last 20: $signed_count"
echo "Health check complete"
}
commit_health_check

What’s the difference between git commit -a and git commit?

Section titled “What’s the difference between git commit -a and git commit?”

git commit -a automatically stages all modified and deleted files before committing; git commit only commits already staged changes.

How do I change the commit message after committing?

Section titled “How do I change the commit message after committing?”

Use git commit —amend -m “new message” to change the last commit message.

Can I commit only part of a file’s changes?

Section titled “Can I commit only part of a file’s changes?”

Yes, use git add —patch to stage specific hunks, then git commit to commit only those staged changes.

What’s the difference between —amend and creating a new commit?

Section titled “What’s the difference between —amend and creating a new commit?”

—amend replaces the last commit instead of creating a new one, effectively rewriting history for that commit.

How do I commit without running pre-commit hooks?

Section titled “How do I commit without running pre-commit hooks?”

Use git commit —no-verify to skip pre-commit hooks.

Use git commit —allow-empty-message -m "" but this is generally not recommended.

How do I see what changes will be committed?

Section titled “How do I see what changes will be committed?”

Use git diff —cached to see staged changes that will be committed.

What’s the difference between author and committer?

Section titled “What’s the difference between author and committer?”

Author is who wrote the code; committer is who created the commit (usually the same person).

Use git commit —date=“2024-01-01 12:00:00” to override the commit date.

How do I create a commit that doesn’t change anything?

Section titled “How do I create a commit that doesn’t change anything?”

Use git commit —allow-empty -m “message” for commits with no file changes.

Yes, use git commit -S to GPG-sign commits for verification.

Use git commit -C to reuse the exact message, or -c to edit it.

—fixup creates a commit that will be automatically squashed with the specified commit during rebase —autosquash.

Can I commit specific files without staging others?

Section titled “Can I commit specific files without staging others?”

Yes, use git commit -m “message” to commit only those files.

Use git commit —amend —author=“New Author ” —no-edit to change the last commit’s author.

—reset-author updates the author information to match the current git config when amending commits.

Yes, use git commit -v to show the diff of all changes in the commit message editor.

Use git commit —dry-run to see what would be committed without actually creating the commit.

What’s the difference between -C and -c options?

Section titled “What’s the difference between -C and -c options?”

-C reuses the commit message exactly; -c opens the editor to modify the reused message.

Use git commit —cleanup=strip to clean up the commit message (remove trailing whitespace, etc.).

Use git commit -s to add a “Signed-off-by:” trailer to the commit message.

Can I commit from a file containing the message?

Section titled “Can I commit from a file containing the message?”

Yes, use git commit -F to read the commit message from a file.

What’s the —pathspec-from-file option for?

Section titled “What’s the —pathspec-from-file option for?”

—pathspec-from-file allows reading file paths to commit from a file instead of command line arguments.

Use git commit —squash= to create a commit message suitable for squashing with the specified commit.

Yes, use git commit —date= to set a custom commit date.

—porcelain provides machine-readable output format for scripting purposes.

Use git commit -q or —quiet to suppress the commit summary message.

Yes, set git config commit.template to use a template file for commit messages.

What’s the —untracked-files option for?

Section titled “What’s the —untracked-files option for?”

—untracked-files shows untracked files in the commit message editor status.

After resolving conflicts, use git commit without -m to get the default merge commit message.

During interactive rebase, use git commit —amend to modify commits, or git rebase —continue after editing.

—short provides shorter output format when doing dry runs.

Use git commit —allow-empty -m “message” to create a commit with no changes.

Use git verify-commit to verify GPG signatures on commits.

  1. Version Control: Recording project milestones and changes
  2. Collaboration: Preparing changes for code review and merging
  3. Documentation: Creating meaningful commit history with descriptive messages
  4. Release Management: Tagging releases and version points
  5. Bug Tracking: Associating commits with issue tracking systems
  6. Audit Trail: Maintaining verifiable history of code changes
  7. Continuous Integration: Automated commit creation in CI/CD pipelines
  8. Code Review: Preparing atomic, reviewable changes