How can I selectively merge or pick changes from another branch in Git?
Solution 1
You use the cherry-pick command to get individual commits from one branch.
If the change(s) you want are not in individual commits, then use the method shown here to split the commit into individual commits. Roughly speaking, you use git rebase -i
to get the original commit to edit, then git reset HEAD^
to selectively revert changes, then git commit
to commit that bit as a new commit in the history.
There is another nice method here in Red Hat Magazine, where they use git add --patch
or possibly git add --interactive
which allows you to add just parts of a hunk, if you want to split different changes to an individual file (search in that page for "split").
Having split the changes, you can now cherry-pick just the ones you want.
Solution 2
I had the exact same problem as mentioned by you above. But I found this clearer in explaining the answer.
Summary:
-
Check out the path(s) from the branch you want to merge,
$ git checkout source_branch -- <paths>... Hint: It also works without `--` like seen in the linked post.
-
or to selectively merge hunks
$ git checkout -p source_branch -- <paths>...
Alternatively, use reset and then add with the option -p
,
$ git reset <paths>...
$ git add -p <paths>...
-
Finally commit
$ git commit -m "'Merge' these changes"
Solution 3
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:
1) You want a true merge.
In this case, you accept the merged files the way Git merged them automatically and then commit them.
2) There are some files you don't want to merge.
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.
3) If you want the version in branchX (and not a true merge).
Run:
git checkout branchX file1
This will retrieve the version of file1
in branchX
and overwrite file1
auto-merged by Git.
4) The last case is if you want to select only specific merges in 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
If you find some merge undesirable then you can
- edit the file directly
- save
git commit
If you don't want to merge file1
and want to retain the version in the current branch
Run
git checkout HEAD file1
If you don't want to merge file2
and only want the version in branchX
Run
git checkout branchX file2
If you want 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
.
Solution 4
I don't like the above approaches. Using cherry-pick is great for picking a single change, but it is a pain if you want to bring in all the changes except for some bad ones. Here is my approach.
There is no --interactive
argument you can pass to git merge.
Here is the alternative:
You have some changes in branch 'feature' and you want to bring some but not all of them over to 'master' in a not sloppy way (i.e. you don't want to cherry pick and commit each one)
git checkout feature
git checkout -b temp
git rebase -i master
# Above will drop you in an editor and pick the changes you want ala:
pick 7266df7 First change
pick 1b3f7df Another change
pick 5bbf56f Last change
# Rebase b44c147..5bbf56f onto b44c147
#
# Commands:
# pick = use commit
# edit = use commit, but stop for amending
# squash = use commit, but meld into previous commit
#
# If you remove a line here THAT COMMIT WILL BE LOST.
# However, if you remove everything, the rebase will be aborted.
#
git checkout master
git pull . temp
git branch -d temp
So just wrap that in a shell script, change master into $to and change feature into $from and you are good to go:
#!/bin/bash
# git-interactive-merge
from=$1
to=$2
git checkout $from
git checkout -b ${from}_tmp
git rebase -i $to
# Above will drop you in an editor and pick the changes you want
git checkout $to
git pull . ${from}_tmp
git branch -d ${from}_tmp
Solution 5
There is another way to go:
git checkout -p
It is a mix between git checkout
and git add -p
and might quite be exactly what you are looking for:
-p, --patch
Interactively select hunks in the difference between the <tree-ish>
(or the index, if unspecified) and the working tree. The chosen
hunks are then applied in reverse to the working tree (and if a
<tree-ish> was specified, the index).
This means that you can use git checkout -p to selectively discard
edits from your current working tree. See the “Interactive Mode”
section of git-add(1) to learn how to operate the --patch mode.
![DocuMar](https://i.stack.imgur.com/6cT3I.png?s=256&g=1)
DocuMar
Updated on July 18, 2022Comments
-
DocuMar almost 2 years
On AIX 6.1, the batchman process does not correctly recognize the time zone of the local machine that is set to GMT, even if, in the IBM Workload Scheduler CPU definition, it is correctly set to the correct timezone. You see the following message in the stdlist log :
"10:29:39 24.11.2015|BATCHMAN:AWSBHT126I Time in CPU TZ (America/Chicago): 2015/11/24 04:29 10:29:39
24.11.2015|BATCHMAN:AWSBHT127I Time in system TZ (America/Chicago): 2015/11/24 10:29 10:29:39
24.11.2015|BATCHMAN:+ 10:29:39 24.11.2015|BATCHMAN:+ AWSBHT128I
Local time zone time differs from workstation time zone time by 360 minutes."Batchman does not recognize the correct time zone because AIX 6.1 uses (International Components for Unicode) ICU libraries to manage the timezone of the system, and these ICU libraries are in conflict with the IBM Workload Scheduler libraries.
-
akaihola over 14 yearsIf changes in your experimental branches are well organized in separate commits, it's better to think in terms of merging selective commits instead of selective files. Most of the answers below assume this is the case.
-
VonC over 13 yearsWouldn't a combination of
git merge -s ours --no-commit
followed by somegit read-tree
be a good solution for this? See stackoverflow.com/questions/1214906/… -
brahn almost 11 yearsA more recent question has a one-line, well-written answer: stackoverflow.com/questions/10784523/…
-
shellter almost 7 yearsThere are very few AIX readers on this forum. Http://ittoolbox.com has a forum for AIX that is active and helpful, but the best place to ask AIX questions is on the IBM support website ( I don't have the exact link, you'll have to search for it). Good luck.
-
shellter almost 7 yearsAND this Q is not about programming as defined for StackOverflow. It may be more appropriate on the S.E. related site serverfault.com (prof. server-or-networking-S.E.-related infra. admin). Use the
flag
link at the bottom of your Q and ask the moderator to move it. Please don't post the same Q on 2 different sites. Please read stackoverflow.com/help/how-to-ask stackoverflow.com/help/dont-ask and stackoverflow.com/help/mcve before posting more Qs here. Good luck -
covener almost 7 yearsSounds like a bug report, not a programming question.
-
Ashutosh Chamoli over 5 yearsCheckout this blog for merging specific files only jasonrudolph.com/blog/2009/02/25/…
-
-
1800 INFORMATION almost 15 yearsI fixed up the formatting - this is a pretty nice method, if you want to do a selection of commits
-
Pistos over 14 yearsBart J's linked article is the best approach. Clear, simple, one command. It's the one I'm about to use. :)
-
dylanfm over 14 yearsI'm using this technique now and it seems to have worked really well.
-
akaihola over 14 yearsThis isn't a real merge. You're picking changes by file instead of by commit, and you'll lose any existing commit information (author, message). Granted, this is good if you want to merge all changes in some files and it's ok that you must re-do all commits. But if files contain both changes to merge and others to discard, one of the methods provided in other answers will serve you better.
-
akaihola over 14 yearsTip: first use the
git cherry
command (see manual first) to identify commits you haven't yet merged. -
mykhal over 14 yearsseems to work, unfortunately, i don't see the changes with
git diff
-
Filip Dupanović almost 14 yearsthis is great if you've created changes that shouldn't be a part of the topical branch your working on, but of some other.
-
okonomichiyaki over 13 years@mykhal and others: this stages the files in the index automatically, so you if you checked out
foo.c
dogit reset HEAD foo.c
to unstage that file and you can then diff it. I found this out after trying it and coming back here to look for an answer to this -
sircolinton over 13 yearsYou might want to change
git rebase -i $to
togit rebase -i $to || $SHELL
, so that the user can callgit --skip
etc, as necessary if the rebase fails. Also worth chaining the lines together with&&
instead of newlines. -
OderWat about 13 yearsto see the changes you could also use:
git diff --cached
-
cdunn2001 about 13 yearsIn some situations, this could be very handy. However, if the changes are in a different branch, you can just checkout from the tip of that branch, as in Bart J's answer above.
-
Abylay about 13 yearsI used a slight variation on this. Instead of merging I cherry-picked. It does the job. The only downside to this approach is you lose the reference to the original commit hash.
-
EMiller over 12 yearsAlso note: you can do multiple files from a given branch all inline, eg
git checkout exp1 path/to/file_a path/to/file_x
-
Alexander Bird over 12 yearsFrom my understanding, this is needlessly more convoluted than the higher-voted answer.
-
Jay over 12 yearsThis is technically the correct answer, the correct answer does appear "convoluted". --- The higher voted answer is just a quick and dirty "does the trick" answer, which for most people is all they are about (:
-
cfi over 12 yearsCareful though: If the
git merge --no-commit branchX
is just a fast-forward, the pointer will be updated, and the --no-commit is thus silently ignored -
ThomasW about 12 yearsUnfortunately, it appears the the link in the answer is dead.
-
Hazok about 12 yearsIf you're going to use diff to manually merge the files, you could just do the diff in the first place and manually make the changes in your local branch rather than checking out first, then diffing, then manually making the changes you already had.
-
radicand almost 12 years@spacemanaki has what I think is the best answer here.
git checkout feature-branch foo.c
followed bygit reset HEAD foo.c
then followed bygit add -p
to pull in the differences you want or exclude bad ones, thengit commit foo.c
to save your changes, andgit checkout foo.c
to reset the index. Worked like a charm. -
gMale over 11 yearsTaking @Zach 's advice worked for me. To expand on it, if you use a difftool, you can use
git difftool origin develop src/main/path/to/file.ext
and bring over the lines of code you need. This works particularly well if you just want to grab a few lines. -
RobM over 11 yearsYour first command (
git merge --no-ff --no-commit -s outs branchname1
) is exactly what I was looking for! Thanks! -
Jean-François Corbett over 11 yearsNot only is the link dead, but it has a WOT poor reputation warning. Therefore I removed it.
-
Tyler Rick over 11 years@akaihola: HEAD^ is correct. See man git-rev-parse: A suffix ^ to a revision parameter means the first parent of that commit object. The prefix ^ notation is used to exclude commits reachable from a commit.
-
Tyler Rick over 11 yearsThis is by far the easiest, simplest method, as long as you only have a manageable number of changes to merge in. I hope more people will notice this answer and upvote it. Example: git checkout --patch exp1 file_to_merge
-
Tyler Rick over 11 yearsSimilar answer posted on this question: stackoverflow.com/a/11593308/47185
-
Daniel C. Sobral over 11 yearsOh, I didn't know checkout had a patch! I did checkout/reset/add -p instead.
-
Adam Grant about 11 yearsAm I the only one who doesn't see an answer here? All I see is "I had the exact same problem as mentioned by you above. But I found this clearer in explaining the answer."
-
Eduardo Costa almost 11 years@cfi What about adding
--no-ff
to prevent that behavior? -
Skunkwaffle almost 11 yearsThis won't merge. It'll just overwrite the changes on master with the changes from the feature1 branch.
-
oHo almost 11 yearsPerfectly, I was looking for this kind of merge where
theirs
overwriteours
=> +1 Cheers ;) -
isherwood over 10 yearsThis is beautiful. I did
git checkout feature <path>/*
to get groups of files. -
Igor Ralic over 10 yearsThis doesn't really merge, it overwrites the file on current branch.
-
Funktr0n about 10 yearsI definitely suggest updating this answer with Eduardo's "--no-ff" option. I read through the whole thing (which was otherwise great) only to have my merge get fast-forwarded.
-
timss about 10 yearsWith multiple branches, required history, need to merge single file(s) and have to change the content of the file before pushing, this seems to be a decent alternative. For example dev => master, but you want to change the a host definition or similar before pushing to master.
-
Thiago Macedo almost 10 yearsThis solution gives the best results and flexibility.
-
Paul Weber almost 10 yearsTo split the commit into individual commits you have to be on the branch where the commit is located. Else you will fail in the 'rebase -i' step, because you cannot find the commit. Happened to me, hope it does not happen to others.
-
owensmartin almost 10 years@igrali That's a useful comment, but compared to the difficulty of the "proper" ways to do this, this is a good workaround. One just has to be very careful.
-
MagicLAMP almost 10 yearsSome times all you want to do is replace the whole file, so this is what I wanted, but you need to make sure you want to lose all the changes you made to this file.
-
superuseroi almost 10 yearsThis almost the best answer I found. please see jasonrudolph.com/blog/2009/02/25/… So clear, concise and it just works!
-
superuseroi almost 10 yearsI just wanted to share another approach which seems the cleanest and less convoluted of them all: jasonrudolph.com/blog/2009/02/25/… total simplicity and awesome
-
Brent Faust over 9 yearsCleanest solution, given that the OP specifically wanted to replace the entire file with the equivalent on another branch:
2. Manual copying of common files into a temp directory followed by ...copying out of the temp directory into the working tree.
-
ws_e_c421 over 9 yearsUnlike the answer with the most votes, this solution preserved my merge history, which is important to me as I weave partial commits back and forth across branches. I didn't try all of the other suggested solutions, so perhaps some of them do this as well.
-
MiamiBeach over 9 yearsAs far as I understand, in case of conflict this 'merge' just replaces the conflicting lines in current branch with lines from source_branch, which is not a merge, it is a replace.
-
7hi4g0 over 9 yearsAccording to this answer
git checkout -p <revision> -- <path>
will be the same as issuing the first three commands you described :) -
Johnny Utahh about 9 years@Pistos, I can find no 'Bart J' listed on this page. Maybe user names/etc have changed some since Oct 2009?
-
Pistos about 9 years@JohnnyUtahh A lot can happen in 6 years. :) Maybe the answer was deleted or removed, or the user has deleted his account, etc. Who knows. :)
-
Saad Malik almost 9 yearsThis was very useful where current_branch had lots of "additional" changes which needed to be preserved. Got the diff of only changes brought in by branch_b as: git diff HEAD...branch_b (yes--three periods does the magic trick).
-
MightyPork almost 9 yearsThis works ok, but added two extra commit objects. Not a huge deal but a bit messy
-
Eric Hu almost 9 years@MightyPork you're right. Unfortunately, since I wrote this so long ago, I'm no longer sure why the "git stash" and "git merge stash" steps are in there instead of a "git commit".
-
MightyPork almost 9 yearsOh that's clear, I think. This way it merges the one file, not necessarily overwriting previous changes on the target branch.
-
maxweber over 8 yearsGood alvinabad; but, sadly, Android Studio says "Partial Commit During a Merge is not allowed"! Used your command, then reviewed the 106 staged to commit files in Android Studio. There I checked the 30 or so I want to put in this branch. Our use case is we have multi-day to week long code review (PR) process step, so I do all the work in a prototype and then spoonfeed changes into the code review. This way I can make progress and not wait on the code reviewers.
-
Spiralis over 8 years@masukomi, On step 2, shouldn't you add the patch-file created in step 1 as an argument?
-
Felipe over 8 yearsThis is not a real merge however it is exactly what I was looking for!
-
Susheel Javadi over 8 yearsI've undeleted the answer. Since it served the purpose I was looking for.
-
infoclogged over 8 yearsTruly the most simplest method. git checkout -p featurebranch filename. And the best thing is when the command is run, it gives you a y/n/e/?/...etc. option to decide how to merge the file. I tried with e and I could even edit the patch before applying ... How cool is it. A true one liner for merging selective files from other branches.
-
Mark Edington over 8 years@EricHu like you commented, there should be no need to bother with the stash and merge. Just do a commit after the checkout of the files from the other branches. The changes are already staged at that point.
-
RamPrasadBismil about 8 yearsThis works .. 1. created a new branch 2.created some files/ made some changes 3. commit 4. checkout the master branch 5. Run git cherry-pick -x hash-of-commit and resolve merge conflicts are you are good to go.
-
Michel about 8 yearsBest solution in company's where coders do regular complete rewrites/rearrangements of modules. This merge method gives maximum control and (p)review.
-
jww almost 8 years@Torek - Yet another awful git solution to sync'ing a dev-branch.... I'll use either (1) manual backup; or (2) separate clone to restore things to where I want them after the complete merge.
-
Kay V almost 8 yearsConfused by the debate over which approach is 'correct'? Consider the difference between files & commits (see Remarks at bottom). OP wants to merge FILES & does not mention COMMITS. The higher-voted answer is specific to files; the accepted answer uses cherry-pick, which is specific to commits. Cherry-pick may be key for merging commits selectively, but it can be very painful for moving files from one branch to another. Though commits are the heart of git's strength, don't forget files still have a role!
-
1800 INFORMATION almost 8 years@ownsourcingdevtraining thanks for the clarification - I don't really use git that much any more, and back when I wrote this answer (7 years ago?) I probably wasn't really aware of the distinction
-
Kay V almost 8 years@1800INFORMATION thanks for your note in return. It's always fun to see how our understandings evolve over time, hey? :) it was great that you gave a solution that worked for the OP and many others. If you feel the distinction between commits and files is worth putting up front, I've proposed language in an edit to your answer that might help guide people in a choice of solution. Please edit further as you see fit, and thanks again!
-
Doktor J almost 8 years@ownsourcingdevtraining I think OP may have accepted the answer because perhaps they're relatively new to git, and were just thinking in terms of files when they really wanted to merge a commit. I came here looking for how to selectively merge commits, but I used "files" in my search ;)
-
node_saini about 7 yearsThe link in the answer did it all. Thanks :)
-
Pablo Adames almost 7 yearsIf you find
file1
did not exist incurrentBranch
and you don't want to commit it as part of the merge, then remove it manually before committing. Trying to do agit checkout HEAD file1
will fail. -
Vance McCorkle over 6 yearsCan't git use logic to distinguish what you have staged from out of date files in your working branch? The out of date files should not be merged, the newer file from the default branch should simply be copied in to the working branch IMO.
-
Arijoon over 6 yearsThis is NOT merging, it's substituting. A closer action to an actual merge by file could be
git diff branch1 branch2 filepath > 1.patch
and thengit apply 1.patch
. Of course it is only going bring pure file changes and nothing else. -
danielricecodes over 6 yearsBIG CAUTION. This merge works in one direction, but the files that you did not include in the merge are seen as DELETED if you decide to merge your upstream master back into the source branch. I use a git-flow like process using a master branch (production main-line), a staging branch (staging server main-line), and topic branches based off of the staging branch. Using this strategy has resulted in my "reverse merge" from master back into staging to competely fail thinking everything I didn't merge from staging to master is deleted. This includes whole files and hunks. YOU ARE WARNED
-
Simon C. over 6 yearsThis is indeed usefull and could be added to what is for me the best answer, the @alvinabad's answer. When doing:
git checkout HEAD file1
to keep the current version and unmerge the filefile1
, one can use-p
option to select part of the file to be merged. thanks for the trick! -
creep3007 about 6 yearsYour link is not working anymore. Can you update it please?
-
djvg about 6 yearsTo expand upon the comment by @PabloAdames: Note that
file1
has already been staged, so to remove the file from staging I would eithergit reset file1
before deleting it manually, orgit add file1
after deleting it manually. -
Amare almost 6 yearsdid you test this? i am sure the files will be replaced from <branch_you_want_to_merge_from> rather than being merged
-
Amare almost 6 yearsthat will completely replace the files content from the source branch rather than merging
-
Keith Tyler over 5 yearsIt doesn't appear to do a merge at all. It simply replaced the HEAD file with the stash file.
-
Black over 5 yearsThe linked post uses
$ git checkout source_branch <paths>...
not$ git checkout source_branch -- <paths>...
. What is right?! -
Black over 5 yearsWho is Bart Js?
-
Irfandy Jip over 4 yearsI was just about to answer like this, I thought I invent new things that haven't been answered yet! But this is the the most simple way to do it. This should be on top!
-
LinusGeffarth over 4 yearsFor me, all changes are rejected. Any idea why?
-
masukomi over 4 yearsinitial thought @LinusGeffarth is that maybe you got the branches backwards when making the patch? will followup outside of SO to see if we can figure it out.
-
Gaspa79 about 4 yearsYEEEEEEEAAAAAAAAAAAAAAAAHHHHHHHHHHHHH
-
rolfedh almost 4 years@Pistos Where can we find this fabled link to Bart's simple answer?
-
Pistos almost 4 years@rolfedh "A lot can happen in 6 years. :) Maybe the answer was deleted or removed, or the user has deleted his account, etc. Who knows. :) – Pistos May 5 '15 at 16:49"
-
Peter Mortensen almost 4 years@Pistos: No, there aren't any deleted answers (you can see that with your 10,000+ reputation points) or deleted users (they would have greyed-out user icons). A user most likely changed his/her screen name. It would nice to have it resolved (as comments to several answers refer to it).
-
Peter Mortensen almost 4 yearsThe link is (effectively) broken: "Authentication Required ...
https://www.sourcemage.org
is requesting your username and password. The site says: 'Restricted Zone'". (It is also redirecting to HTTPS.) -
Peter Mortensen almost 4 yearsIf it doesn't refer to this answer, then "Bart J" is now "Cory" and the link is sourcemage.org/Git_Guide (as "1800 INFORMATION" did not change name (it was "1800 INFORMATION" on 2009-05-07 - before Pistos' comment), and nosatalian's answer doesn't have any links).
-
Peter Mortensen almost 4 yearsThough nosatalian's answer did have a link in previous versions. It was removed (due to being "broken and dangerous").
-
Peter Mortensen almost 4 yearsBut the sourcemage.org link is also broken.
-
Peter Mortensen almost 4 yearsCan you link directly to the other answer you are referring to (user names are not stable enough as they can change at any time)? (Sort by "Oldest" to restrict the number of possible answers (before yours).)
-
pooja almost 4 yearsthanks, I just removed it as I'm not sure where to find the original at this point
-
Wade almost 4 years@PeterMortensen good point, I'm pretty sure I got the right one in there now.
-
Jan Stefanides almost 4 yearsThis works the same as
git checkout branch ...
below - the local changes not present inbranch
are removed(!). They are marked as "removed" in the patch file as plain diff does not check the commits history. -
Hashim Aziz almost 4 yearsDoesn't
git reset --hard
get rid of committed changes? -
John almost 4 yearsThis worked perfectly, The only change I made was to do a
git merge --continue
instead of the finalgit commit
. Thanks! -
Eric Duminil over 3 yearsAs mentioned by others, it's really not a merge, and it won't be obvious at all from the graph that it's merge, even a partial one.
-
pepoluan over 3 years@Prometheus according to documentation: "Resets the index and working tree. Any changes to tracked files in the working tree since <commit> are discarded." So the commit itself is safe.
-
Simon Hessner almost 3 yearsThis was the easiest answer I could find. The only weird thing are the two commit messages that you get, but the merging itself works perfectly.
-
Rosdi Kasim over 2 yearsAnswer from @alvinabad is much easier.
-
Stunner over 2 yearsWhat does this do? The comments in your answer fail to explain how this command behaves.
-
Jia Huei over 2 yearsI found that running
git merge --quit
aftergit merge --no-ff --no-commit <other_branch>
allows the changes to be made as regular commits (not as merge) -
Coderer about 2 yearsApparently at some point I downvoted this answer because I didn't want to lose commit history. Today, I didn't care about the commit history, I just needed to selectively take part of one branch during a merge/rebase, on a change-by-change basis. The answer here worked perfectly.