update-ref Git Command Guide
The git update-ref command safely updates the object name stored in a reference (ref), providing atomic operations for branch and tag management. It’s a low-level command that offers precise control over Git references with safety guarantees and transactional behavior.
git update-ref Syntax:
Section titled “git update-ref Syntax:”git update-ref [-d] [-z] [--stdin] [--no-deref] [--create-reflog] [-m <reason>] [--no-refs] <ref> <newvalue> [<oldvalue>]git update-ref [--no-deref] [-m <reason>] --stdin [--no-refs]Reference Update Options:
Section titled “Reference Update Options:”| Option | Description |
|---|---|
-d, --delete | Delete reference |
-z | Use NUL character as delimiter |
--stdin | Read updates from stdin |
--no-deref | Don’t dereference symbolic refs |
--create-reflog | Create reflog entry |
-m <reason> | Reason for update (reflog) |
Safety Options:
Section titled “Safety Options:”| Option | Description |
|---|---|
<oldvalue> | Expected current value (CAS) |
--no-refs | Don’t verify refs namespace |
Parameters:
Section titled “Parameters:”| Parameter | Description |
|---|---|
<ref> | Reference to update |
<newvalue> | New object SHA-1 or ref |
<oldvalue> | Expected current value |
Understanding Reference Operations:
Section titled “Understanding Reference Operations:”Git Reference Types:
Section titled “Git Reference Types:”Reference Hierarchy:├── Direct References: Point to objects│ ├── refs/heads/main -> commit SHA-1│ ├── refs/tags/v1.0 -> commit SHA-1│ └── refs/remotes/origin/main -> commit SHA-1│└── Symbolic References: Point to other refs ├── HEAD -> refs/heads/main ├── ORIG_HEAD -> commit SHA-1 └── MERGE_HEAD -> commit SHA-1Atomic Operations:
Section titled “Atomic Operations:”Atomic Reference Updates:├── Compare-and-Swap (CAS): Verify old value before update├── Transactional: All-or-nothing updates├── Lock-Free: Uses filesystem locking├── Safe Concurrency: Multiple processes can update safely└── Reflog Integration: Automatic history trackingReference Resolution:
Section titled “Reference Resolution:”Reference Resolution Chain:Reference Name├── refs/heads/feature -> Direct ref├── refs/tags/v1.0 -> Direct ref├── HEAD -> Symbolic ref -> refs/heads/main└── refs/remotes/origin/HEAD -> Symbolic ref -> refs/remotes/origin/mainBasic Update-Ref Operations:
Section titled “Basic Update-Ref Operations:”Updating Branch References:
Section titled “Updating Branch References:”# Update branch to new commitgit update-ref refs/heads/main abc123def456
# Update with safety checkgit update-ref refs/heads/main abc123def456 789def012345
# Update symbolic refgit update-ref HEAD refs/heads/developCreating and Deleting References:
Section titled “Creating and Deleting References:”# Create new branch referencegit update-ref refs/heads/feature-branch abc123def456
# Create tag referencegit update-ref refs/tags/v1.0 abc123def456
# Delete referencegit update-ref -d refs/heads/old-branch
# Delete taggit update-ref -d refs/tags/old-tagSafe Reference Updates:
Section titled “Safe Reference Updates:”# Update only if current value matchesgit update-ref refs/heads/main new-commit-sha current-commit-sha
# Update with reflog messagegit update-ref -m "Merge pull request #123" refs/heads/main merge-commit-sha
# Create reflog entrygit update-ref --create-reflog refs/heads/feature new-commit-shaAdvanced Update-Ref Scenarios:
Section titled “Advanced Update-Ref Scenarios:”Batch Reference Operations:
Section titled “Batch Reference Operations:”# Update multiple refs from stdingit update-ref --stdin << EOFupdate refs/heads/main abc123def456 789def012345update refs/heads/develop def456ghi789 abc123def456delete refs/heads/old-featureEOF
# Process refs with NUL delimiterprintf 'update refs/heads/main\x00abc123\x00789def\x00' | git update-ref -z --stdinSymbolic Reference Management:
Section titled “Symbolic Reference Management:”# Update HEAD to point to different branchgit update-ref HEAD refs/heads/release
# Update remote HEADgit update-ref refs/remotes/origin/HEAD refs/remotes/origin/main
# Create symbolic referencegit update-ref refs/heads/current refs/heads/mainReference Maintenance:
Section titled “Reference Maintenance:”# Clean up dangling referencesgit for-each-ref --format='%(refname)' | while read -r ref; do if ! git show-ref --verify "$ref" >/dev/null 2>&1; then echo "Removing dangling ref: $ref" git update-ref -d "$ref" fidone
# Update remote tracking branchesgit update-ref refs/remotes/origin/main "$(git rev-parse origin/main)"Transactional Operations:
Section titled “Transactional Operations:”# Atomic multi-ref updateupdate_multiple_refs() { local main_commit="$1" local develop_commit="$2"
# Use stdin for atomic updates git update-ref --stdin << EOFupdate refs/heads/main $main_commit $(git rev-parse refs/heads/main)update refs/heads/develop $develop_commit $(git rev-parse refs/heads/develop)EOF
if [ $? -eq 0 ]; then echo "Successfully updated both branches" else echo "Failed to update branches atomically" fi}
# Usageupdate_multiple_refs "abc123" "def456"Configuration and Best Practices:
Section titled “Configuration and Best Practices:”Git Configuration for Update-Ref:
Section titled “Git Configuration for Update-Ref:”# Configure reflog behaviorgit config core.logAllRefUpdates true # Enable reflog for all refsgit config core.logAllRefUpdates always # Always create reflog
# Configure reference verificationgit config receive.denyDeletes false # Allow ref deletiongit config receive.denyDeleteCurrent false # Allow deleting current branch
# Configure reflog expirationgit config gc.reflogExpire 90.days # Keep reflogs for 90 daysgit config gc.reflogExpireUnreachable 30.daysSafe Update-Ref Operations:
Section titled “Safe Update-Ref Operations:”# Always verify before updatesafe_update_ref() { local ref="$1" local new_value="$2" local expected_old="${3:-}"
# Get current value local current_value current_value=$(git rev-parse "$ref" 2>/dev/null || echo "")
# Check if update is needed if [ "$current_value" = "$new_value" ]; then echo "Ref $ref already at $new_value" return 0 fi
# Perform safe update if [ -n "$expected_old" ]; then git update-ref "$ref" "$new_value" "$expected_old" else git update-ref "$ref" "$new_value" fi}
# Backup refs before major operationsbackup_refs() { echo "Backing up references..."
git for-each-ref --format='%(refname) %(objectname)' > refs-backup.txt
echo "Backup saved to refs-backup.txt"}
# Restore refs from backuprestore_refs() { local backup_file="${1:-refs-backup.txt}"
echo "Restoring references from $backup_file..."
while read -r ref sha; do git update-ref "$ref" "$sha" 2>/dev/null || echo "Failed to restore $ref" done < "$backup_file"
echo "Reference restoration complete"}Performance Optimization:
Section titled “Performance Optimization:”# Batch reference updatesbatch_update_refs() { echo "Performing batch reference updates..."
# Collect updates updates_file=$(mktemp) echo "update refs/heads/main abc123 $(git rev-parse refs/heads/main)" >> "$updates_file" echo "update refs/heads/develop def456 $(git rev-parse refs/heads/develop)" >> "$updates_file"
# Execute atomically git update-ref --stdin < "$updates_file"
# Cleanup rm "$updates_file"}
# Optimize reflog operationsoptimize_reflog() { echo "Optimizing reflog operations..."
# Disable reflog for performance git config core.logAllRefUpdates false
# Perform updates # ... update operations ...
# Re-enable reflog git config core.logAllRefUpdates true}Integration with Development Workflows:
Section titled “Integration with Development Workflows:”Branch Management Automation:
Section titled “Branch Management Automation:”#!/bin/bash# Automated branch management with update-ref
create_feature_branch() { local feature_name="$1" local base_branch="${2:-main}"
echo "Creating feature branch: $feature_name"
# Get base commit base_commit=$(git rev-parse "$base_branch")
# Create branch reference git update-ref "refs/heads/feature/$feature_name" "$base_commit"
# Set upstream git config "branch.feature/$feature_name.remote" origin git config "branch.feature/$feature_name.merge" "refs/heads/feature/$feature_name"
echo "Feature branch created and configured"}
# Automated branch cleanupcleanup_merged_branches() { echo "Cleaning up merged branches..."
git for-each-ref --format='%(refname:short) %(objectname)' refs/heads/feature/ | while read -r branch sha; do if git merge-base --is-ancestor "$sha" main; then echo "Deleting merged branch: $branch" git update-ref -d "refs/heads/$branch" fi done
echo "Branch cleanup complete"}
# Usagecreate_feature_branch "user-authentication"cleanup_merged_branchesRelease Management:
Section titled “Release Management:”# Release tagging with update-refcreate_release_tag() { local version="$1" local release_commit="$2"
echo "Creating release tag: v$version"
# Create annotated tag object tag_object=$(git mktag << EOFobject $release_committype committag v$versiontagger $(git config user.name) <$(git config user.email)> $(date +%s) +0000
Release v$version
Release notes:- Feature 1- Feature 2- Bug fixesEOF)
# Update tag reference git update-ref "refs/tags/v$version" "$tag_object"
echo "Release tag v$version created"}
# Automated version bumpingbump_version() { local new_version="$1"
echo "Bumping version to $new_version"
# Update version file echo "$new_version" > VERSION
# Commit version change version_commit=$(git commit-tree -p HEAD -m "Bump version to $new_version" VERSION)
# Update main branch git update-ref refs/heads/main "$version_commit"
# Create version tag git update-ref "refs/tags/v$new_version" "$version_commit"
echo "Version bumped to $new_version"}
# Usagecreate_release_tag "2.1.0" "abc123def456"bump_version "2.1.0"Repository Synchronization:
Section titled “Repository Synchronization:”# Repository synchronization with update-refsync_repository_refs() { local remote_name="$1"
echo "Synchronizing references with $remote_name..."
# Fetch remote refs git fetch "$remote_name"
# Update remote tracking branches git for-each-ref --format='%(refname:short)' "refs/remotes/$remote_name/" | while read -r remote_ref; do local_ref="refs/heads/${remote_ref#refs/remotes/$remote_name/}"
# Skip HEAD if [[ "$remote_ref" == */HEAD ]]; then continue fi
remote_commit=$(git rev-parse "$remote_ref") git update-ref "$local_ref" "$remote_commit" 2>/dev/null && \ echo "Updated $local_ref to $remote_commit" || \ echo "Skipped $local_ref (possibly protected)" done
echo "Repository synchronization complete"}
# Usagesync_repository_refs "origin"Troubleshooting Common Issues:
Section titled “Troubleshooting Common Issues:”Reference Update Conflicts:
Section titled “Reference Update Conflicts:”# Handle concurrent update conflictshandle_update_conflict() { local ref="$1" local new_value="$2" local max_attempts=5 local attempt=1
while [ $attempt -le $max_attempts ]; do current_value=$(git rev-parse "$ref" 2>/dev/null || echo "")
if git update-ref "$ref" "$new_value" "$current_value"; then echo "Successfully updated $ref on attempt $attempt" return 0 fi
echo "Update conflict on attempt $attempt, retrying..." sleep 1 ((attempt++)) done
echo "Failed to update $ref after $max_attempts attempts" return 1}
# Usagehandle_update_conflict "refs/heads/main" "new-commit-sha"Reference Corruption:
Section titled “Reference Corruption:”# Detect and fix corrupted referencesfix_corrupted_refs() { echo "Checking for corrupted references..."
git for-each-ref | while read -r sha type ref; do if ! git cat-file -e "$sha" 2>/dev/null; then echo "Corrupted reference: $ref -> $sha"
# Try to find correct commit correct_sha=$(git log --oneline -1 --grep="$ref" --format=%H 2>/dev/null || echo "")
if [ -n "$correct_sha" ]; then echo "Fixing $ref to point to $correct_sha" git update-ref "$ref" "$correct_sha" else echo "Cannot fix $ref, removing..." git update-ref -d "$ref" fi fi done
echo "Reference corruption check complete"}Permission Issues:
Section titled “Permission Issues:”# Handle permission issues with referencesfix_ref_permissions() { echo "Fixing reference permissions..."
# Fix .git/refs permissions find .git/refs -type f -exec chmod 644 {} \; find .git/refs -type d -exec chmod 755 {} \;
# Fix packed-refs permissions [ -f .git/packed-refs ] && chmod 644 .git/packed-refs
# Fix reflog permissions find .git/logs -type f -exec chmod 644 {} \; 2>/dev/null || true
echo "Reference permissions fixed"}
# Test reference accesstest_ref_access() { local ref="$1"
if git update-ref "$ref" "$(git rev-parse HEAD)" 2>/dev/null; then echo "Reference $ref is writable" else echo "Reference $ref is not writable" return 1 fi}Reflog Issues:
Section titled “Reflog Issues:”# Fix reflog problemsrepair_reflog() { local ref="$1"
echo "Repairing reflog for $ref..."
reflog_file=".git/logs/${ref#refs/}"
# Backup current reflog cp "$reflog_file" "${reflog_file}.backup" 2>/dev/null || true
# Rebuild reflog from history git log --oneline --format="%H %ct %s" "$ref" | while read -r commit timestamp message; do echo "$commit $timestamp reflog-entry" >> "${reflog_file}.new" done
# Replace reflog mv "${reflog_file}.new" "$reflog_file" 2>/dev/null || echo "Could not update reflog"
echo "Reflog repair attempt complete"}
# Clean old reflog entriesclean_reflog() { echo "Cleaning old reflog entries..."
# Expire old entries git reflog expire --all --expire=30.days
# Pack reflogs git reflog pack
echo "Reflog cleanup complete"}Symbolic Reference Issues:
Section titled “Symbolic Reference Issues:”# Fix broken symbolic referencesfix_symbolic_refs() { echo "Checking symbolic references..."
# Check HEAD if ! git rev-parse HEAD >/dev/null 2>&1; then echo "HEAD is broken, fixing..." git update-ref HEAD refs/heads/main fi
# Check other symbolic refs for sym_ref in ORIG_HEAD MERGE_HEAD CHERRY_PICK_HEAD; do if git show-ref "$sym_ref" >/dev/null 2>&1; then target=$(git rev-parse "$sym_ref" 2>/dev/null) if [ -z "$target" ]; then echo "Removing broken $sym_ref" git update-ref -d "$sym_ref" fi fi done
echo "Symbolic reference check complete"}Real-World Usage Examples:
Section titled “Real-World Usage Examples:”Advanced Branch Management:
Section titled “Advanced Branch Management:”#!/bin/bash# Advanced branch management with update-ref
# Atomic branch operationsatomic_branch_operations() { echo "=== Atomic Branch Operations ==="
# Create multiple branches atomically create_branches() { local base_commit="$1" shift local branches=("$@")
echo "Creating branches atomically..."
# Prepare updates updates="" for branch in "${branches[@]}"; do updates+="update refs/heads/$branch $base_commit\n" done
# Execute atomically echo -e "$updates" | git update-ref --stdin
if [ $? -eq 0 ]; then echo "Successfully created ${#branches[@]} branches" else echo "Failed to create branches atomically" fi }
# Rename branch safely rename_branch() { local old_name="$1" local new_name="$2"
echo "Renaming branch $old_name to $new_name..."
# Get current commit current_commit=$(git rev-parse "refs/heads/$old_name")
# Create new branch git update-ref "refs/heads/$new_name" "$current_commit"
# Update HEAD if pointing to old branch if [ "$(git rev-parse HEAD)" = "$current_commit" ]; then git update-ref HEAD "refs/heads/$new_name" fi
# Delete old branch git update-ref -d "refs/heads/$old_name"
echo "Branch renamed successfully" }
# Interactive operations echo "Branch Operations:" echo "1. Create multiple branches" echo "2. Rename branch safely"
read -p "Select operation (1-2): " op
case "$op" in 1) read -p "Base commit: " base read -p "Branches (space-separated): " -a branches create_branches "$base" "${branches[@]}" ;; 2) read -p "Old branch name: " old read -p "New branch name: " new rename_branch "$old" "$new" ;; esac}
atomic_branch_operationsTag Management System:
Section titled “Tag Management System:”# Advanced tag management with update-reftag_management_system() { echo "=== Tag Management System ==="
# Create annotated tag manually create_annotated_tag() { local tag_name="$1" local commit="$2" local message="$3"
echo "Creating annotated tag: $tag_name"
# Create tag object tag_object=$(git mktag << EOFobject $committype committag $tag_nametagger $(git config user.name) <$(git config user.email)> $(date +%s) +0000
$messageEOF)
# Update tag reference git update-ref "refs/tags/$tag_name" "$tag_object"
echo "Annotated tag $tag_name created" }
# Batch tag operations batch_tag_operations() { echo "Performing batch tag operations..."
# Prepare tag updates updates=""
# Example: Tag all release commits git log --oneline --grep="Release" --format="%H %s" | while read -r commit subject; do version=$(echo "$subject" | sed 's/Release v//') if [[ "$version" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then updates+="update refs/tags/v$version $commit\n" fi done
# Execute batch update echo -e "$updates" | git update-ref --stdin
echo "Batch tag operations complete" }
# Tag cleanup cleanup_tags() { local pattern="$1"
echo "Cleaning up tags matching: $pattern"
git for-each-ref --format='%(refname)' "refs/tags/$pattern" | while read -r tag_ref; do echo "Removing tag: ${tag_ref#refs/tags/}" git update-ref -d "$tag_ref" done
echo "Tag cleanup complete" }
# Interactive tag management echo "Tag Management Options:" echo "1. Create annotated tag" echo "2. Batch tag operations" echo "3. Cleanup tags"
read -p "Select option (1-3): " option
case "$option" in 1) read -p "Tag name: " tag_name read -p "Commit: " commit read -p "Message: " message create_annotated_tag "$tag_name" "$commit" "$message" ;; 2) batch_tag_operations ;; 3) read -p "Pattern to match: " pattern cleanup_tags "$pattern" ;; esac}
tag_management_systemRepository Maintenance Automation:
Section titled “Repository Maintenance Automation:”# Repository maintenance with update-refautomated_maintenance() { echo "=== Automated Repository Maintenance ==="
# Clean up stale branches cleanup_stale_branches() { local max_age_days="${1:-90}"
echo "Cleaning up branches older than $max_age_days days..."
git for-each-ref --format='%(refname) %(creatordate:format:%s)' refs/heads/ | while read -r ref create_time; do current_time=$(date +%s) age_days=$(( (current_time - create_time) / 86400 ))
if [ "$age_days" -gt "$max_age_days" ]; then # Check if merged branch_commit=$(git rev-parse "$ref") if git merge-base --is-ancestor "$branch_commit" main 2>/dev/null; then echo "Removing merged branch: ${ref#refs/heads/} (age: ${age_days} days)" git update-ref -d "$ref" fi fi done
echo "Stale branch cleanup complete" }
# Update remote references update_remote_refs() { local remote="${1:-origin}"
echo "Updating remote references for $remote..."
# Fetch latest git fetch "$remote"
# Update remote refs git ls-remote "$remote" | while read -r sha ref; do if [[ "$ref" == refs/heads/* ]]; then local_ref="refs/remotes/$remote/${ref#refs/heads/}" git update-ref "$local_ref" "$sha" fi done
echo "Remote references updated" }
# Reflog maintenance maintain_reflog() { echo "Maintaining reflog..."
# Expire old entries git reflog expire --all --expire=30.days
# Pack reflogs git reflog pack
# Clean unreachable reflog entries git reflog expire --all --expire-unreachable=now
echo "Reflog maintenance complete" }
# Interactive maintenance echo "Maintenance Options:" echo "1. Clean up stale branches" echo "2. Update remote references" echo "3. Maintain reflog"
read -p "Select option (1-3): " option
case "$option" in 1) read -p "Max age in days (default: 90): " max_age cleanup_stale_branches "${max_age:-90}" ;; 2) read -p "Remote name (default: origin): " remote update_remote_refs "${remote:-origin}" ;; 3) maintain_reflog ;; esac}
automated_maintenanceCustom Git Commands:
Section titled “Custom Git Commands:”# Custom Git commands using update-refcustom_git_commands() { echo "=== Custom Git Commands ==="
# Safe force push safe_force_push() { local branch="$1" local remote="${2:-origin}"
echo "Performing safe force push of $branch to $remote..."
# Get remote commit remote_commit=$(git rev-parse "refs/remotes/$remote/$branch" 2>/dev/null || echo "")
# Get local commit local_commit=$(git rev-parse "refs/heads/$branch")
# Check if force is necessary if [ "$remote_commit" = "$local_commit" ]; then echo "Branch is already up to date" return 0 fi
# Check if local is descendant of remote if git merge-base --is-ancestor "$remote_commit" "$local_commit" 2>/dev/null; then echo "Safe to push (local is descendant)" git update-ref "refs/remotes/$remote/$branch" "$local_commit" else echo "Force push required - checking safety..."
# Additional safety checks if [ -n "$remote_commit" ]; then # Check how many commits would be lost lost_commits=$(git rev-list "$remote_commit..HEAD" | wc -l) if [ "$lost_commits" -gt 10 ]; then echo "Warning: Would lose $lost_commits commits" read -p "Continue? (yes/no): " confirm if [ "$confirm" != "yes" ]; then return 1 fi fi fi
# Perform force update git update-ref "refs/remotes/$remote/$branch" "$local_commit" echo "Force push completed safely" fi }
# Branch snapshot create_branch_snapshot() { local branch="$1" local snapshot_name="${2:-snapshot-$(date +%Y%m%d-%H%M%S)}"
echo "Creating snapshot of branch $branch as $snapshot_name..."
current_commit=$(git rev-parse "refs/heads/$branch") git update-ref "refs/snapshots/$snapshot_name" "$current_commit"
echo "Snapshot created: refs/snapshots/$snapshot_name -> $current_commit" }
# Restore from snapshot restore_from_snapshot() { local snapshot_name="$1" local target_branch="$2"
echo "Restoring $target_branch from snapshot $snapshot_name..."
snapshot_commit=$(git rev-parse "refs/snapshots/$snapshot_name") git update-ref "refs/heads/$target_branch" "$snapshot_commit"
echo "Branch $target_branch restored from snapshot" }
# Interactive custom commands echo "Custom Git Commands:" echo "1. Safe force push" echo "2. Create branch snapshot" echo "3. Restore from snapshot"
read -p "Select command (1-3): " cmd
case "$cmd" in 1) read -p "Branch: " branch read -p "Remote (default: origin): " remote safe_force_push "$branch" "${remote:-origin}" ;; 2) read -p "Branch: " branch read -p "Snapshot name (optional): " snapshot create_branch_snapshot "$branch" "$snapshot" ;; 3) read -p "Snapshot name: " snapshot read -p "Target branch: " branch restore_from_snapshot "$snapshot" "$branch" ;; esac}
custom_git_commands