Git合并分支时如何保留指定文件的特定内容,其余复用另一分支?
Absolutely! You can achieve this conditional merge behavior in Git using custom merge drivers (to handle content preservation) and Git hooks (to manage filename cleanup). Let’s walk through the setup step by step, tailored to your exact scenario:
Core Idea
When merging between master and dev:
- Merging into
dev: Keepxxx-dev.txt, preserve itsID=02line, and replace all other content with what’s inmaster’sxxx-master.txt. - Merging into
master: Keepxxx-master.txt, preserve itsID=01line, and replace all other content with what’s indev’sxxx-dev.txt.
Step 1: Create a Custom Merge Script
This script will handle the content merging logic, preserving the target branch’s ID line while pulling other content from the source branch.
- Create a directory for Git scripts (if you don’t have one):
mkdir -p ~/.git/scripts - Create a script named
merge-preserve-id-name.shin this directory with the following content:#!/bin/bash # Get the target branch (the branch we're merging INTO) TARGET_BRANCH=$(git rev-parse --abbrev-ref HEAD) OURS="$1" # Current branch's file (target branch) BASE="$2" # Common ancestor file THEIRS="$3" # Source branch's file (the branch we're merging from) RESULT="$4" # Output file for merged content if [ "$TARGET_BRANCH" = "dev" ]; then # Preserve ID=02 from dev's file, take rest from master's file PRESERVED_ID=$(grep "ID=02" "$OURS") # Filter out any ID lines from the source branch's content grep -v "ID=" "$THEIRS" > "$RESULT" # Append the preserved ID line echo "$PRESERVED_ID" >> "$RESULT" elif [ "$TARGET_BRANCH" = "master" ]; then # Preserve ID=01 from master's file, take rest from dev's file PRESERVED_ID=$(grep "ID=01" "$OURS") grep -v "ID=" "$THEIRS" > "$RESULT" echo "$PRESERVED_ID" >> "$RESULT" else # Fallback to Git's default merge if not merging into master/dev git merge-file "$OURS" "$BASE" "$THEIRS" > "$RESULT" fi - Make the script executable:
chmod +x ~/.git/scripts/merge-preserve-id-name.sh
Step 2: Configure Git to Use the Merge Driver
Add the custom merge driver to your Git config. Open ~/.gitconfig or your project’s .git/config file and add:
[merge "preserve-id-name"] name = Preserve target branch's ID and filename during merge driver = ~/.git/scripts/merge-preserve-id-name.sh %O %A %B %L
%O: Path to the common ancestor file%A: Path to the target branch’s file%B: Path to the source branch’s file%L: Path to the merged result file
Step 3: Assign the Driver to Your Files
Create a .gitattributes file in your project root to tell Git which files to apply this driver to:
xxx-*.txt merge=preserve-id-name
This matches both xxx-master.txt and xxx-dev.txt.
Step 4: Clean Up Extra Files with a Post-Merge Hook
Since Git will treat xxx-master.txt and xxx-dev.txt as separate files by default, we need to delete the unwanted file after merging.
- Create a
post-mergehook in your project’s.git/hooksdirectory:#!/bin/bash TARGET_BRANCH=$(git rev-parse --abbrev-ref HEAD) if [ "$TARGET_BRANCH" = "dev" ]; then # Remove master's file if it exists after merging into dev if [ -f "xxx-master.txt" ]; then git rm xxx-master.txt git commit -m "Cleanup: Remove xxx-master.txt after merging into dev" fi elif [ "$TARGET_BRANCH" = "master" ]; then # Remove dev's file if it exists after merging into master if [ -f "xxx-dev.txt" ]; then git rm xxx-dev.txt git commit -m "Cleanup: Remove xxx-dev.txt after merging into master" fi fi - Make the hook executable:
chmod +x .git/hooks/post-merge
Testing the Setup
- Merge
masterintodev: Git will updatexxx-dev.txtto usemaster’s content except forID=02, then automatically deletexxx-master.txt. - Merge
devintomaster: Git will updatexxx-master.txtto usedev’s content except forID=01, then automatically deletexxx-dev.txt.
Notes
- Double-check branch names in scripts (if your branches use uppercase like
MasterorDev, adjust the script accordingly). - If your ID lines have more specific formatting, tweak the
greppatterns to match exactly.
内容的提问来源于stack exchange,提问作者Traceur

