2

Having both typical branches, master with A and B files and later create dev branch:

  • I might create new files at dev and maybe modify B but,
  • lets say that either I change or even delete A
  • When I decide to merge them so master might look like dev
  • I want the A file (or any other file or folders) to remain the SAME, no matter how the merged branch looks like.

How can I achieve this?

Would git reset or git revert help me solve it?

diegoaguilar
  • 8,179
  • 14
  • 80
  • 129

2 Answers2

4

Do the merge with --no-commit. Once the automatic part of the merge is finished, git stops (the same way it would if it cannot complete the merge itself) and you may now alter the merge result in whatever way you like, including checking out the desired version of file A:

git checkout branch -- A

or:

git checkout --ours -- A

(etc).

Once the tree has been adjusted to your satisfaction (if you have automated tests, use them!), git add if needed, and git commit the result to complete the merge.

(You can automate some or all of this, if you like.)


Edit to add example. Let's say you want to merge dev into master, but keep master's version of xyz.html. (I removed xyz.html in branch dev. I also added file foo, and made no other changes.) Let's also use --no-ff to force a real merge. (Otherwise git may be able to do a fast-forward merge, if branch dev is exclusively ahead of master. In this case our --no-commit has no effect, since git won't attempt a commit anyway.)

$ git checkout master
Switched to branch 'master'
$ git merge --no-ff --no-commit dev
Removing xyz.html
Automatic merge went well; stopped before committing as requested
$ git checkout master -- xyz.html

(You can check out any particular version of xyz.html: the above just gets the version from the tip of branch master. Since you are actually on branch master there are many other ways to spell this; that's just the most explicit I could think of.)

$ git status
On branch master
All conflicts fixed but you are still merging.
  (use "git commit" to conclude merge)

Changes to be committed:

    new file:   foo

$ git commit

(at this point the editor opens, as with any other commit; writing out the file and exiting produces)

[master 9746054] Merge branch 'dev'
$ 
torek
  • 448,244
  • 59
  • 642
  • 775
  • "Where" (at what branch) should I be when doing either `git checkout branch -- A` or `git checkout --ours -- A`? – diegoaguilar Sep 09 '14 at 10:38
  • If you are merging `dev` into `master`, you must necessarily be on `master` when you issue the `git merge` command. This form of `git checkout` (with `--` and paths; you can omit the `--` if and only if the path names do not look like branch names or flags) does not change your current branch, so you will still be on the same branch you are merging-into. – torek Sep 09 '14 at 10:42
  • Hmm can you edit your question and explain quite step by step like with an example? I got bit confused – diegoaguilar Sep 09 '14 at 10:53
  • Thanks! When should I not and should use the `--no-ff` argument? – diegoaguilar Sep 11 '14 at 11:09
  • Well, "when" is more detailed than just the one example above, but this is a case where allowing fast-forward means there is no actual merge, so it is in fact required here if the merge would be a non-merge fast-forward. See http://stackoverflow.com/questions/18126297/when-to-use-the-no-ff-merge-option-in-git and the selected answer for more. – torek Sep 11 '14 at 18:36
  • I'm satisfied with your answer, however next time I did a commit and even when I had to pull, I noticed such A files to be "there" again... So I wonder whether I always have to do these git commands – diegoaguilar Sep 18 '14 at 05:36
  • Every time you merge (and `git pull` is just a script that does `git fetch` followed by `git merge`: http://stackoverflow.com/a/292359/1256452) git does the same thing: find "merge base", diff merge-base with tip of current branch, and diff merge-base with to-be-merged commit. Then it combines the changes from "to-be-merged" with the changes found in the first diff. If the first diff makes no changes to file `F` and second makes a change, git "wants to" take the change. So it depends on what's in these two diffs. – torek Sep 18 '14 at 05:54
1

Several ways how to do this:

I. Assuming the file version you wish to keep on master is commited.

git checkout dev
git add -u                           <--- add tracked files to the commit
git commit -m "my commit"            <--- the new commit
git push                             <--- by default: to origin, but you may explicitly choose

git checkout master         
git log                              <--- check the last commit's hash
git pull dev                         <--- either clean, or merge required
git checkout <hash> file/to/restore  <--- get the master's version of the file

II. Create patches of the dev's commits and manually edit them.

git format-patch -<how_many> <sha>   <--- note: <sha> is literally there,
// send the patches to server, e.g. scp
// edit the patches, e.g. gedit 0001blabla.patch
git am <patch>                       <-- apply the patch

III. Create commits on dev excluding the change to the file, push the commits to master. Then create a commit on dev actually changing the file. As a result, commits on master are a subset of dev's.

There are probably tons of other too.

hauron
  • 4,550
  • 5
  • 35
  • 52
  • It'll pull the commits from the dev branch onto the master branch (if it's possible). Similiar to git merge. You may need to resolve the conflicts though – hauron Sep 09 '14 at 10:57
  • `git pull` is pretty much just `git fetch` followed by `git merge`, so this will make a merge that removes the file. You can of course restore the file as shown, and make another commit, or even use `git commit --amend`, but that's kind of the long way around. – torek Sep 09 '14 at 11:02