I\'m using Git on a new project that has two parallel -- but currently experimental -- development branches:
master
: import of existing codebase pl
This is my workflow for merging selective files.
# Make a new branch (this will be temporary)
git checkout -b newbranch
# Grab the changes
git merge --no-commit featurebranch
# Unstage those changes
git reset HEAD
(You can now see the files from the merge are unstaged)
# Now you can chose which files are to be merged.
git add -p
# Remember to "git add" any new files you wish to keep
git commit
To selectively merge files from one branch into another branch, run
git merge --no-ff --no-commit branchX
where branchX
is the branch you want to merge from into the current branch.
The --no-commit
option will stage the files that have been merged by Git without actually committing them. This will give you the opportunity to modify the merged files however you want to and then commit them yourself.
Depending on how you want to merge files, there are four cases:
In this case, you accept the merged files the way Git merged them automatically and then commit them.
For example, you want to retain the version in the current branch and ignore the version in the branch you are merging from.
To select the version in the current branch, run:
git checkout HEAD file1
This will retrieve the version of file1
in the current branch and overwrite the file1
automerged by Git.
Run:
git checkout branchX file1
This will retrieve the version of file1
in branchX
and overwrite file1
auto-merged by Git.
file1
.In this case, you can edit the modified file1
directly, update it to whatever you'd want the version of file1
to become, and then commit.
If Git cannot merge a file automatically, it will report the file as "unmerged" and produce a copy where you will need to resolve the conflicts manually.
To explain further with an example, let's say you want to merge branchX
into the current branch:
git merge --no-ff --no-commit branchX
You then run the git status
command to view the status of modified files.
For example:
git status
# On branch master
# Changes to be committed:
#
# modified: file1
# modified: file2
# modified: file3
# Unmerged paths:
# (use "git add/rm <file>..." as appropriate to mark resolution)
#
# both modified: file4
#
Where file1
, file2
, and file3
are the files git have successfully auto-merged.
What this means is that changes in the master
and branchX
for all those three files have been combined together without any conflicts.
You can inspect how the merge was done by running the git diff --cached
;
git diff --cached file1
git diff --cached file2
git diff --cached file3
git commit
file1
and want to retain the version in the current branchRun
git checkout HEAD file1
file2
and only want the version in branchX
Run
git checkout branchX file2
file3
to be merged automatically, don't do anything.Git has already merged it at this point.
file4
above is a failed merge by Git. This means there are changes in both branches that occur on the same line. This is where you will need to resolve the conflicts manually. You can discard the merged done by editing the file directly or running the checkout command for the version in the branch you want file4
to become.
Finally, don't forget to git commit
.
If you don't have too many files that have changed, this will leave you with no extra commits.
1. Duplicate branch temporarily
$ git checkout -b temp_branch
2. Reset to last wanted commit
$ git reset --hard HEAD~n
, where n
is the number of commits you need to go back
3. Checkout each file from original branch
$ git checkout origin/original_branch filename.ext
Now you can commit and force push (to overwrite remote), if needed.
A simple approach for selective merging/committing by file:
git checkout dstBranch
git merge srcBranch
// Make changes, including resolving conflicts to single files
git add singleFile1 singleFile2
git commit -m "message specific to a few files"
git reset --hard # Blow away uncommitted changes
You can use read-tree
to read or merge a given remote tree into the current index, for example:
git remote add foo git@example.com/foo.git
git fetch foo
git read-tree --prefix=my-folder/ -u foo/master:trunk/their-folder
To perform the merge, use -m
instead.
See also: How do I merge a sub directory in Git?
If you only need to merge a particular directory and leave everything else intact and yet preserve history, you could possibly try this... create a new target-branch
off of the master
before you experiment.
The steps below assume you have two branches target-branch
and source-branch
, and the directory dir-to-merge
that you want to merge is in the source-branch
. Also assume you have other directories like dir-to-retain
in the target that you don't want to change and retain history. Also, assumes there are merge conflicts in the dir-to-merge
.
git checkout target-branch
git merge --no-ff --no-commit -X theirs source-branch
# the option "-X theirs", will pick theirs when there is a conflict.
# the options "--no--ff --no-commit" prevent a commit after a merge, and give you an opportunity to fix other directories you want to retain, before you commit this merge.
# the above, would have messed up the other directories that you want to retain.
# so you need to reset them for every directory that you want to retain.
git reset HEAD dir-to-retain
# verify everything and commit.