Reputation: 2401
Once upon a time, there were two branches:
--[stable]--hotfix1--h2--h3
\
\--[develop]--refactor1--r2--r3
I need to merge stable
into develop
, but I'm in a bit of a pickle.
develop
has been refactored with a different directory structure. and Git is not able to follow the change.
(stable)
|-app
| |-scripts
| |-site
| |-**ALL THE CODE
(develop)
|-app
| |-modules
| |**ALL THE CODE
expected - When I run git merge
, git applies the hotfixes in stable
to the new file path in develop
.
actual - Git marks the files with hotfixes as "deleted by us" because they have the old directory structure.
stable
to the new directory structure in develop
?Upvotes: 0
Views: 320
Reputation: 204668
You can help Git by simulating a merge with everything already renamed. Using Bash for example,
# Mark this as the branch to be merged.
git update-ref --stdin <<<'create MERGE_HEAD stable'
printf '%s\t\t%s\n' $(git rev-parse MERGE_HEAD) "branch 'stable'" |
>$(git rev-parse --git-dir)/MERGE_MSG git fmt-merge-msg \
$([[ $(git config --bool merge.log) = true ]] && echo --log)
# This outputs a tree object with some paths transformed.
refactor-tree() {
(
index1= index2=
trap 'rm -f "${index1}" "${index2}"' 0
index1=$(mktemp) index2=$(mktemp)
GIT_INDEX_FILE=${index1} git read-tree "$@"
GIT_INDEX_FILE=${index2} git read-tree --empty
GIT_INDEX_FILE=${index1} git ls-files -s -z |
while IFS=$'\t' read -d '' -r info file; do
[[ ${file} = app/scripts/site/* ]] && file=app/modules/${file#*/*/*/}
printf '%s\t%s\0' "${info}" "${file}"
done |
GIT_INDEX_FILE=${index2} git update-index --index-info
GIT_INDEX_FILE=${index2} git write-tree
)
}
# Update the index for the 3-way merge.
git read-tree -m --aggressive -u \
$(refactor-tree $(git merge-base MERGE_HEAD HEAD)) \
$(git write-tree) \
$(refactor-tree MERGE_HEAD)
# Resolve the merge.
git merge-index -o git-merge-one-file -a
# Commit the results.
git commit
The above was tested on a demo repository created like this:
git init
mkdir -p app/scripts/site
cat >app/scripts/site/README.md <<EOF
Hello, world!
=============
EOF
git add app/scripts/site/README.md
git commit -m 'base'
git checkout -b stable
sed -i -e '1s/w/W/' app/scripts/site/README.md
git add app/scripts/site/README.md
git commit -m 'hotfix'
git checkout master -b develop
git mv app/scripts/site app/modules
rm -rf app/scripts
git commit -m 'refactor'
cat >>app/modules/README.md <<EOF
blah blah blah
EOF
git add app/modules/README.md
git commit -m 'blah'
Notice that if you remove the =============
line, the merge will fail due to a conflict in that file, but it gets context markers like usual. You can resolve it by hand and try to commit again.
Upvotes: 1
Reputation: 179
It might work to just change the directory structure for stable
to match develop
(in a commit), you could then just merge them together. I would just do this manually (with a file browser), but if you are really itching to use git commands for the whole task, you could find the commit on develop
that changed the directory structure, cherry-pick that onto stable
, and then the merge would probably apply properly (with some merge conflicts possibly).
Upvotes: 1