in Education by
I have an old, out-of-sync project code in the master branch. Several files have been deleted, added, re-written and thoroughly edited. I want to force merge stable latest code from development branch into master. I am trying to force merge, but still get merge conflicts. Here are the steps I followed: ➜ project git:(development) git checkout master ➜ project git:(master) git pull ➜ project git:(master) git merge -s recursive -X theirs development CONFLICT (modify/delete): vendors/popup/magnific-popup.css deleted in HEAD and modified in development. Version development of vendors/popup/magnific-popup.css left in tree. CONFLICT (modify/delete): vendors/popup/jquery.magnific-popup.min.js deleted in HEAD and modified in development. Version development of vendors/popup/jquery.magnific-popup.min.js left in tree. CONFLICT (modify/delete): vendors/owl-carousel/assets/animated.css deleted in HEAD and modified in development. Version development of vendors/owl-carousel/assets/animated.css left in tree. ... several similar conflicts I tried doing a rm of all files in my master branch ➜ project git:(master) git reset --hard HEAD ➜ project git:(master) rm -rf * ➜ project git:(master) git merge -s recursive -X theirs development Still get the same conflicts. What am I doing wrong? Edit: Here is a graph for better understanding about what is going on. At some point, unrelated histories were also pushed. JavaScript questions and answers, JavaScript questions pdf, JavaScript question bank, JavaScript questions and answers pdf, mcq on JavaScript pdf, JavaScript questions and solutions, JavaScript mcq Test , Interview JavaScript questions, JavaScript Questions for Interview, JavaScript MCQ (Multiple Choice Questions)

1 Answer

0 votes
by
I think you don't want this kind of merge at all. I think what you want is a "theirs strategy" merge, which Git doesn't offer. It can still be done: see VonC's answer here. But read on to be sure that this is what you want, before you use it. There are two important things going on here, both sort-of captured by your command sequence: git checkout master git merge -s recursive -X theirs development (I left out the step that didn't do anything). The first is that most merges—including that from the default -s recursive merge strategy—work by finding a common starting point: a shared merge base commit. To draw this as a rather simple case, consider the following commit graph: C--D--E <-- master (HEAD) / ...--o--B \ F--G--H <-- development Obviously your own graph will be much hairier, but in the end, this all works out the same: Git takes the current commit, as indicated by your current branch master, which is commit E, as one of the three inputs to the merge process. Git takes the commit you specify, in this case commit H because development is the one you said to look at, as the second of the three inputs to the merge process. The third input is computed from the graph. We start at each of the two tip commits and begin walking backwards, the way Git always does. Commit E leads back to D, which leads to C and then to B. Meanwhile commit H leads to G to F to B. Commit B is on both branches, and it is, in graph terms, the lowest common ancestor.1 (Informally, it's the one closest to both branch tips. "Closest" breaks down in complex graphs, but for simple ones like this, that's what lowest common ancestor means.) That makes it the best shared commit, and hence the merge base. What happens now is pretty simple in general terms, but gets sticky in some details. Git starts with the merge base commit in terms of "desired result". That is, the contents Git starts with are those from the snapshot in commit B. To these contents, Git needs to apply the combination of any changes that you made and any changes that they made. So Git needs to run two git diff commands: git diff --find-renames hash-of-B hash-of-E: what we changed on master git diff --find-renames hash-of-B hash-of-H: what they changed on development If the merge base is close to both tips, as it is here, probably each of these two diffs doesn't show all that much. Combining the two sets of changes will be easy and straightforward. If we changed line 12 of README.md, and they didn't touch README.md at all, Git takes our change, giving our version of README.md to go in the new merge commit. If they touched a different line of README.md, Git puts our two changes together: both get applied to B:README.md to produce the README.md for the new commit. This process repeats for all the files. If we and they both touched the same line(s) of the same files, though, Git would normally declare a merge conflict and stop, leaving us to clean up the mess. That's where the -X theirs option comes in: this is an eXtended option, passed on to the -s strategy.2 In this case, the recursive strategy treats the theirs extended-option as meaning: in the case of a conflict, throw away my change and use theirs. Note that if there isn't a conflict, Git will use our change! Sometimes that's what we want. If it is what we want, -X theirs is the right idea. If it's not what we want, -X theirs is the wrong idea. So that's where you need to decide: do we use -X theirs, or do we use a -s theirs that we have to construct as in VonC's answer? 1It's the lowest common ancestor because computer scientists draw their trees upside down: A | B / \ C D / \ \ E F G The common ancestors of E and F here are C, B, and A, but C is the lowest one. The common ancestors of F and G are B and A; B is lowest. Git's commit graph is a directed acyclic graph or DAG, rather than a tree, so "LCA" is not as simple as it is in a tree, and there can be multiple LCAs (or no LCA at all) given two nodes in a graph. Git handles all this sensibly, for some definition of sensible. 2Git calls -X a strategy option, but that sounds exactly like the -s strategy argument. It's literally an option to the strategy, hence Git's poorly-chosen name. I think eXtended option is a better name, in part because it explains the -X. If you don't want -X theirs: see the other answer I linked There's not much more to say: -s theirs was once a Git merge strategy. It isn't any more. You can still synthesize it, in any number of ways. My favorite is actually the plumbing command variety in Michal Soltys' answer. If you do want -X theirs: why is it complaining of conflicts? I mentioned above that the merge process—the to merge part of git merge—is "pretty simple ... but gets sticky in some details." You have just hit one of those details. The massive git diffs that Git gets from diffing the merge base it found, vs each of the two tip commits you have specified, has a lot of cases of files that were completely deleted by one side, but modified by the other side: ...--B--o--o--...--o--o <-- master (HEAD) \ o--o--...--o--o <-- development Somewhere in that massive chain of anonymous o commits along the top, "we" (base vs master) deleted some file. "They" (base vs development) changed that file. Git doesn't know how to combine "deleted" with "changed". I call these high level conflicts, because they are changes to the very nature or existence of a file, rather than to the individual lines within a file. Well, I also call it that because Git itself calls the part of the code that combines individual lines the "low level merge driver", so these must be the opposite, high level. These kinds of conflicts—whether add/add, modify/delete, rename/delete, or what—always cause a -s recursive git merge to stop and let you fix up the mess. The extended options are only given to the low level merge driver invoked by the strategy. In fact, the only strategy that doesn't stop is the -s ours strategy. When you use the -s ours strategy, that one totally ignores what's in "their" commit. Git doesn't even bother looking at the merge base at all—it just uses what's in our commit as the merge result. Of course, -s ours takes ours. You wanted something that took theirs, at least for this particular case, maybe for all cases. But if you really don't want the equivalent of -s theirs, but rather -X theirs with taking their entire file in these cases, you're stuck with resolving each of these conflicts after-the-fact. You can do it with a script (which you must write yourself). That's a little tricky though. The trick is to use git ls-files --stage: you'll see that, for each file for which Git complained: CONFLICT (modify/delete): vendors/popup/magnific-popup.css deleted in HEAD and modified in development. Version development of vendors/popup/magnific-popup.css left in tree. Git will have an entry at stage #1 for the name (vendors/popup/magnific-popup.css), and another entry at stage #3 (theirs), but no entry at stage #2 (ours). To resolve this, use git add to write the stage-3 entry from the work-tree into the index at stage zero: git add will remove the stage 1 and 3 copies. You can just collect up all such file names and pass them all to git add.

Related questions

0 votes
    How can we force “git pull” to overwrite local files?...
asked Jan 7, 2021 in Technology by JackTerrance
0 votes
    When you run git fetch from my local repo, will it update your local code and target branch? A. Yes, the command ... new commits and keep them in a separate branch in local repo...
asked Dec 20, 2022 in Education by JackTerrance
0 votes
    My git workspace is dirty, there are some local modifications. When I use the command git pull origin master it ... Ansible git module? Select the correct answer from above options...
asked Feb 8, 2022 in Education by JackTerrance
0 votes
    I don't want to rename a remote branch, as described in the Rename master branch for both local and remote ... and remote branch name Select the correct answer from above options...
asked Jan 30, 2022 in Education by JackTerrance
0 votes
    How to push a new local branch to a remote Git repository and track it too?...
asked Jan 7, 2021 in Technology by JackTerrance
0 votes
    How can we rename a local Git branch?...
asked Jan 7, 2021 in Technology by JackTerrance
0 votes
    When you run git fetch from my local repo, will it update your local code and target branch? (1)Yes, the command ... new commits and keep them in a separate branch in local repo...
asked Oct 26, 2020 in Technology by JackTerrance
0 votes
    How do you delete untracked local files from your current working tree? Select the correct answer from above options...
asked Jan 30, 2022 in Education by JackTerrance
0 votes
    How to remove local (untracked) files from the current Git working tree?...
asked Jan 7, 2021 in Technology by JackTerrance
0 votes
    Merge the Pull request in GitHub for the updates made to starfeature branch. Which channel would receive notification ... . Stakeholders C. Starprojectteam D. None of the options...
asked Dec 23, 2022 in Technology by JackTerrance
0 votes
    Merge the Pull request in GitHub for the updates made to starfeature branch. Which channel would receive notification ... . Stakeholders C. Starprojectteam D. None of the options...
asked Dec 16, 2022 in Education by JackTerrance
0 votes
    Which of the following adds all new files to local repository? (a) git add . (b) git add -u ... questions and answers pdf, Data Science interview questions for beginners...
asked Oct 29, 2021 in Education by JackTerrance
0 votes
    Create a new Pull request. Review the changes between master and starfeature branch, and confirm by clicking Create ... . Stakeholders C. Starprojectteam D. None of the options...
asked Dec 23, 2022 in Technology by JackTerrance
0 votes
    Which of the following creates new commit when you pull new changes from master to the feature branch? A. git rebase master B. git merge master C. git pull origin master...
asked Dec 20, 2022 in Technology by JackTerrance
0 votes
    How will you identify if the branch is already merged into master?...
asked Nov 4, 2020 in Technology by JackTerrance
...