Update/pull from remote repo when when you start a new day cd into project – pull from origin the remote branch:
what this does is to disable a push to “origin” – so only “spiffy-origin” will work on this site moving forward
https://stackoverflow.com/questions/49715421/does-the-order-of-git-merging-matter
Suppose I have two branches, A and B. Do the following properties hold?
- Merging
A into B conflicts if and only if merging B into A conflicts.
- The contents of my files after merging
A into B is the same as the contents of my files after merging B into A.
Assuming there are no conflicts, the content of the merge is the same.
@Maroun That is my hunch as well, but is that actually documented somewhere? Or, does it logically follow from the known properties of the merging algorithms?
cmaster's answer is correct, with caveats. Let's start by noting these items / assumptions:
- There is always a single merge base commit. Let's call this commit B, for base.
- The other two inputs are also single commits. Let's call them L for left / local (
--ours) and R for right / remote (--theirs).
The first assumption is not necessarily true. If there are multiple merge base candidates, it is up to the merge strategy to do something about this. The two standard two-head merge strategies are recursive and resolve. The resolve strategy simply picks one at (apparent) random. The recursive strategy merges the merge bases two at a time, and then uses the resulting commit as the merge base. The one chosen by resolve can be affected by the order of arguments to git merge-base and hence to git merge, so that's one caveat right there. Because the recursive strategy can do more than one merge, there's a second caveat here that is difficult to describe yet, but it applies only if there are more than two merge bases.
The second assumption is much more true, but note that the merge code can run on a partially-modified work-tree. In this case all bets are off, since the work-tree does not match either L or R. A standard git merge will tell you that you must commit first, though, so normally this is not a problem.
Merge strategies matter
We already noted the issue with multiple merge bases. We're assuming a two-head merge as well.
Octopus merges can deal with multiple heads. This also change the merge base computation, but in general octopus merge won't work with cases that have complicated merge issues and will just refuse to run where the order might matter. I would not push hard on it though; this is another case where the symmetry rule is likely to fail.
The -s ours merge strategy completely ignores all other commits so merge order is obviously crucial here: the result is always L. (I am fairly sure that -s ours does not even bother computing a merge base B.)
You can write your own strategy and do whatever you want. Here, you can make the order matter, as it does with -s ours.
High level merging (with one merge base): file name changes
Git now computes, in effect, two change-sets from these three snapshots:
- L – B, or
git diff --find-renames *B L*
- R – B, or
git diff --find-renames *B R*
The rename detectors here are independent—by this I mean neither affects the other; both use the same rules though. The main issue here is that it's possible for the same file in B to be detected as renamed in both change-sets, in which case we get what I call a high level conflict, specifically a rename/rename conflict. (We can also get high level conflicts with rename/delete and several other cases.) For a rename/rename conflict, the final name that Git chooses is the name in L, not the name in R. So here, the order matters in terms of final file name. This does not affect the work-tree merged content.
Low level merging
At this point we should take a small tour of Git's internals. We have now paired up files in B-vs-L and in B-vs-R, i.e., we know which files are "the same" files in each of the three commits. However, the way Git stores files and commits is interesting. From a logical point of view, Git has no deltas: each commit is a complete snapshot of all files. Each file, however, is just a pair of entities: a path name P and a hash ID H.
In other words, at this point, there is no need to walk through all the commits leading from B to either L or R. We know that we have some file F, identified by up to three separate path names (and as noted above, Git will use the L path in most cases, but use the R path if there is only one rename in the B-vs-R side of the merge). The complete contents of all three files are available by direct lookup: HB represents the base file content, HL represents the left-side file, and HR represents the right-side file.
Two files match exactly if and only if their hashes match.1 So at this point Git just compares the hash IDs. If all three match, the merged file is the same as the left and right and base files: there is no work. If L and R match, the merged file is the L or R content; the base is irrelevant as both sides made the same change. If B matches either L or R but not the other, the merged file is the non-matching hash. Git only has to do the low-level merge if there is a potential for a low-level merge conflict.
So now, Git extracts the three contents and does the merge. This works on a line-by-line basis (with lines grouped together when multiple adjacent lines are changed):
- If both left and right sides touched only different source lines, Git will take both changes. This is clearly symmetric.
- If left and right touched the same source lines, Git will check whether the change itself is also the same. If so, Git will take one copy of the change. This, too, is clearly symmetric.
- If left and right touched the same lines, but made different changes, Git will declare a merge conflict. The work-tree content will depend on the order of the changes, since the work-tree content has
<<<<<<< HEAD ... ||||||| base ... ======= ... other >>>>>>> markers (the base section is optional, appearing if you choose diff3 style).
The definition of the same lines is a little tricky. This does depend on the diff algorithm (which you may select), since some sections of some files may repeat. However, Git always uses a single algorithm for computing both L and R, so the order does not matter here.
1To put this another way, if you manage to produce a Doppelgänger file—one that has different content from, but the same hash as, some existing file, Git simply refuses to put that file into the repository. The shattered.it PDF is not such a file, because Git prefixes the file's data with the word blob and the size of the file, but the principle applies. Note that putting such a file into SVN breaks SVN—well, sort of.
-X options are obviously asymmetric
You can override merge conflict complaints using -X ours or -X theirs. These direct Git to resolve conflicts in favor of the L or R change respectively.
Merging makes a merge commit, which affects merge base computation
This symmetry principle, even with the above caveats, is fine for a single merge. But once you have made a merge, the next merge you run will use the modified commit graph to compute the new merge base. If you have two merges that you intend to do, and you do them as:
git merge one (and fix conflicts and commit if needed)
git merge two (fix conflicts and commit if needed)
then even if everything is symmetric in each merge, that does not mean that you will necessarily get the same result as if you run:
git merge two
git merge one
Whichever merge runs first, you get a merge commit, and the second merge now finds a different merge base.
This is particularly important if you do have conflicts that you must fix before finishing whichever merge goes first, since that also affects the L input to the second git merge command. It will use the first merge's snapshot as L, and the new (maybe different) merge base as B, for two of its three inputs.
This is why I mentioned that -s recursive has potential order differences when working with multiple merge bases. Suppose there are three merge bases. Git will merge the first two (in whatever order they pop out of the merge base computation), commit the result (even if there are merge conflicts—it just commits the conflicts in this case), and then merge that commit with the third commit and commit the result. The final commit here is then the input B. Only if all parts of this process are symmetric will that final B result be order-insensitive. Most merges are symmetric, but we saw all the caveats above.
Thanks for supplementing my very high-level, imprecise answer with this low-level, precise, technical detail answer :-)
– cmaster – reinstate monica
Apr 8, 2018 at 19:37
https://www.varonis.com/blog/git-branching
Merging Branches
Once you’ve completed work on your branch, it is time to merge it into the main branch. Merging takes your branch changes and implements them into the main branch. Depending on the commit history, Git performs merges two ways: fast-forward and three-way merge. Let’s examine both of these based on the branches and commit history in the following diagram.
When you merge the hotfix branch into the main branch, Git will move the main branch pointer forward to commit nr7jk. Git does this because the hotfix branch shares a direct ancestor commit with the main branch and is directly ahead of its commit. This commit is a fast-forward merge.
Once you merge the hotfix branch, continue working on the feature1 branch. As you continue making commits on the feature1 branch, the commit history diverges.
Git is unable to move the pointer to the latest commit like in a fast-forward commit. To bring the feature1 branch into the main branch, Git performs a three-way merge. Git takes a snapshot of three different commits to create a new one:The common commit both branches share (a90hb)The latest commit of the branch (az84f)The commit of the branch to merge into (nr7jk)
Merging Branches in a Local RepositoryTo merge branches locally, use git checkoutto switch to the branch you want to merge into. This branch is typically the main branch. Next, use git mergeand specify the name of the other branch to bring into this branch. This example merges the jeff/feature1 branch into the main branch. Note that this is a fast-forward merge.git checkout main git merge jeff/feature1
Work continues on the main and other branches, so they no longer share a common commit history. Now a developer wants to merge the jeff/feature2 branch into the main branch. Instead, Git performs a three-way (or recursive) merge commit.git checkout main git merge jeff/feature2
Merging Branches to Remote RepositoryIf you create a branch in your local repository, the remote repository is not aware of the branch’s existence. Before you can push the branch code in the remote repository, you set the remote repository as the upstream branch using the git pushcommand. This command simultaneously sets the upstream branch and pushes the branch contents to the remote repository.git push --set-upstream origin <branch name>
Merging Main into a BranchWhile you are working on your branch, other developers may update the main branch with their branch. This action means your branch is now out of date of the main branch and missing content. You can merge the main branch into your branch by checking out your branch and using the same git merge command.git checkout <branch name> git merge main
Git FAQsWhat is creating a branch in Git?Creating a branch takes a snapshot of the existing code so you can work on it independently of the main branch.How do I create a new branch in Git?Use the git branch command and specify the branch name, e.g., git branch feature1.How can I view which branch is active?Use git branch to view available branches and which one is active. Git typically designates the active branch with an asterisk and a different colored font.How can I switch to working on another branch?Use git checkout and the name of the branch to make it active.Can I create a branch inside another branch?Yes, specify the name of the branch to base the new branch, e.g., git branch feature-bug feature1.My branch only exists locally. How can I add my branch to my remote Git repository?Yes, use the git push command to set the upstream branch, e.g., git push –set-upstream origin .How can I update the main branch with my branch’s changes?Switch to the main branch using the git checkout command, then merge the branch using the git merge command along with the branch name.How can I delete a branch?When you are done with a branch, delete it using the git branch command and the -d switch, e.g., git branch -d feature1.ClosingGit branching is a powerful feature that allows teams to work on the code independently of each other. Knowing how to create, name, and merge branches are essential skills for any developer, systems administrator, or DevOps engineer.

https://www.delftstack.com/howto/git/git-pull-master-into-branch/
Git Pull Master Into Branch
Git Git Pull
Created: February-17, 2022
- Git Pull Master Into Another Branch
- Use the
git merge Command to Pull Changes From master Into Another Branch
- Use the
git rebase Command to Pull Changes From master Into Another Branch
- Use the
git pull Command to Pull Changes From master Into Another Branch
While developing software with the Git tool, you can create different branches for different features. When making changes to master, those changes are not automatically added to other branches.
This article will explain how to pull all changes from master into another branch in Git.
When using the Git tool, you may need to pull the changes you made in the master to a different branch. These changes are not transferred automatically, so you have to make them manually.
The rest of the article will explain how to pull changes from the master to the dev branch in three different ways.
Note
Because it may be considered dehumanizing toward enslaved people, the master branch has been renamed to main.
Merge
Use the git merge Command to Pull Changes From master Into Another Branch
First, we need to switch to the branch we want to work. The checkout command updates the files in the working tree according to the specified branch.
Use the following command to switch to the dev branch.
git checkout dev
The git fetch command downloads objects and refs from another repository. Use the below command to update your branch if the main branch is changed.
git fetch origin
The git merge command incorporates changes from the named commits into the current branch. Finally, you need to use the following command to merge the changes.
git merge origin/main

Rebase
Use the git rebase Command to Pull Changes From master Into Another Branch
Use the command below to switch to the dev branch.
git checkout dev
Use the fetch command to update the dev branch if the main branch is changed.
git fetch origin
The git rebase command reapplies commits on top of another branch. Use the following command to reapply commits on the dev branch.
git rebase origin/main

Pull
Use the git pull Command to Pull Changes From master Into Another Branch
Use the command below to switch to the dev branch.
git checkout dev
The git pull command fetches from and integrates with another branch. The --allow-unrelated-histories parameter can be used to merge histories that do not share a common ancestor when merging projects.
Use the following command to get the changes from the main.
git pull origin main --allow-unrelated-histories

Write for us
DelftStack articles are written by software geeks like you. If you also would like to contribute to DelftStack by writing paid articles, you can check the write for us page.
Overwrite Local Changes in Git
Difference Between Git Fetch and Git Pull
Pull Changes From a Specific Branch in Git
Pull Changes From Another Branch in Git
https://stackoverflow.com/questions/61069101/how-do-i-pull-changes-from-a-branch-in-master-to-a-subbranch
I checked out branch B1, did a pull, then merged it with B2.
You can either merge or rebase the branch b1 to branch b2.
git checkout b2
git merge b1
or
git checkout b2
git rebase b1
I tried the first option with the merge, but it says already up to date. However, I know it's not the case when I compare against the github commi thistory. Maybe it's pulling from master somehow?
Try to pull first before merging or rebasing. git checkout b2 git pull similarly pull for branch b1 and then perform the merge or rebase
Than you! That worked. I checked out branch B1, did a pull, then merged it with B2.
Breakdown
So I have a branch B1 which is a branch of master. I later created branch B2 from branch B1. However, when I do git pull in B2, I'm not pulling the changes from branch B1. How do I pull changes from B1? Thank you.
2 Answers
I recommend avoiding git pull entirely, at least (or especially) if you're just starting with Git. All git pull does is run git fetch, then run a second Git command for you. The problem is that this obscures what is really happening, preventing you from learning what you need to know.
What you need to know starts with what a commit really is and does, because Git is all about commits. Git is not about files, though a commit does hold files; and it's not even really about branches either, though branch names like b1 and b2 help you—or at least Git—find commits. But while commits hold files, and branch names hold commit hash IDs, Git is really all about the commits.
So, each commit:
- Holds a snapshot of all of your files. That's a full snapshot, not changes since the previous commit.
- Holds some extra information—some metadata—such as your name and email address, and why you made the commit you made. Most of this is just for other humans, but there's a key element in the metadata that's for Git itself, which we'll get to in a moment.
- Has a hash ID. That hash ID is a big ugly string of letters and digits. It looks random, though it's entirely not-random. In fact, the hash ID is a cryptographic checksum of the complete contents of the commit: the files-as-snapshot, and the metadata.
The result of all this is that once made, no part of any commit can ever change. You can take everything out of a commit, make changes to it somewhere else, and then make a new commit from the result, but if you've changed even one single bit anywhere—your name, your log message, one bit of some source file, whatever—what you get is a new and different commit. So commit hash IDs are guaranteed to find one particular commit, and every Git uses the same hash algorithm, so all Gits everywhere use the same hash IDs for the same commits.
How branches grow, or,there is no such thing as a sub-branch
The next thing you need to know is that there is no such thing as a sub-branch.
Given that every commit has its own unique hash ID, we're still left with a problem: how do we find commits? The hash IDs look random, and certainly are not in any sort of useful order. This is where Git's internal metadata, and branch names, come in.
Every commit holds, as part of its metadata, a list of parent commit hash IDs. Usually there is just one hash ID here. That one hash ID is the (singular) parent of this commit. This ties all commits together, one by one, backwards:
... <-F <-G <-H
where H stands for the hash ID of the last commit in the chain. Commit H itself records the actual hash ID of earlier commit G, so by looking inside H we can find the number—the hash ID—that lets us find G. Commit G stores the hash ID of earlier commit F, and so on.
We've now reduced the problem to finding commit H. The way we do that is with a branch name like master or b1. We store the raw hash ID of commit H into the name, giving us:
...--F--G--H <-- b1
Each branch name holds exactly one commit hash ID. If we make a second branch b2, we must pick one of the various existing commits, and make b2 hold that hash ID. Typically we might pick the current commit, i.e., the one with hash H:
...--F--G--H <-- b1, b2
Now we need to remember which name we're using. Git uses the special name HEAD (in all uppercase like this) for that. There are several ways to draw that; here, I'll just attach HEAD in parentheses to one of these branch names:
...--F--G--H <-- b1 (HEAD), b2
or:
...--F--G--H <-- b1, b2 (HEAD)
At this point, let's make a new commit, in the usual way: modify something, git add, and git commit. Git builds the snapshot for the new commit from Git's index—something we won't describe properly here, but this index is why you have to run git add all the time–and the appropriate metadata, including a log message you must write. This new commit gets a new, unique hash ID. The data for the new commit is the new snapshot, and the metadata is what you said, except for the parent: that comes from what Git knows, which is that the current commit is H at this time. So new commit I points back to existing commit H:
...--F--G--H
\
I
and now Git updates whichever branch name HEAD is attached to. If that's b2, the name b2 now holds the hash ID of commit I:
...--F--G--H <-- b1
\
I <-- b2 (HEAD)
Note that commits up through H are now on both branches, while commit I is only on b1. The name HEAD remains attached to the current branch, but now the current commit is commit I.
Merging
Suppose you start with:
...--G--H <-- master (HEAD)
and then create names b1 and b2, both pointing to existing commit H. You then select b1 to work on, with git checkout b1, and make two commits:
I--J <-- b1 (HEAD)
/
...--G--H <-- master, b2
Note that b2 has not yet moved. Now you run git checkout b2 to select commit H again. The snapshots you made for I and J are still there, frozen for all time, but now you're working with the snapshot from H again. You can now make a couple of commits here on b2, giving:
I--J <-- b1
/
...--G--H <-- master
\
K--L <-- b2 (HEAD)
Note that, at this point, you could git checkout master and make new commits there:
o--o <-- b1
/
...--o--o--o--o--o--o <-- master (HEAD)
\
o--o <-- b2
We won't worry about this just yet, but note that nothing happened to any existing commit or any other branch name. Each time we added new commits, the current branch name moved. The new commits all just added to the existing graph of all-commits-so-far. It's totally impossible to change any existing commit, but we never did. All we did was add new commits that link back to the existing ones, and then change the branch names.
Let's go back to the idea of merging, though. We didn't make any new master commits after all, and if we git checkout b1, and temporarily stop drawing in the name master (because it will get in the way), we have:
I--J <-- b1 (HEAD)
/
...--G--H
\
K--L <-- b2
We can now run git merge b2, or we can run git checkout b2; git merge b1. Git will now do its best to combine work, because git merge is about combining work.
Now, each commit holds a snapshot, but combining work requires looking at changes. What Git does here is to use its internal difference engine, which you can invoke yourself with git diff. To make this work, Git first has to find the best common commit: a commit that is on both branches, and not too different from the latest commit on each branch.
Here, it's super-obvious which commit is the best common commit. That's commit H. So Git will now compare the snapshot in H to the snapshot in whichever commit we picked with our git checkout—the commit HEAD is attached to. If we assume that's b1, the commit for this comparison is J:
git diff --find-renames <hash-of-H> <hash-of-J> # what we changed
This tells Git what "we" changed on b1, with respect to the common starting point. Then Git diffs the other pairing:
git diff --find-renames <hash-of-H> <hash-of-L> # what they changed
This tells Git what "they" changed on b2, with respect to the same starting point.
The merge operation now combines these changes, file by file. If we changed line 42 of main.py and they didn't touch main.py at all, Git takes our change. If they did touch main.py too, but not line 42, Git takes their change as well. If we both touched line 42, we'd better both have changed it the same way. If not, Git declares a merge conflict and leaves us with a mess.
Assuming there are no merge conflicts—the above is not a complete list of possible conflicts, just the obvious kind—Git will be able to combine the two sets-of-changes and apply all those changes to all the files as they appear in commit H. That way, the new commit that Git is about to make has our changes from J, but also has their changes from L.
At this point, Git makes the new commit. As usual, the new commit has a snapshot: that's the one Git built by combining changes. As usual, the new commit has a parent; since we're on branch b1, this parent is J. But—not as usual—the new commit has a second parent too. Since we told Git to merge commit L, this second parent is L.
Having made the commit, Git drags our current branch name forward:
I--J
/ \
...--G--H M <-- b1 (HEAD)
\ /
K--L <-- b2
and this is the result of running git merge.
Git is distributed
Now, you're probably not the only person who makes commits. Other people make commits too. You typically start by cloning a repository, perhaps from GitHub, perhaps from somewhere else. This gets you all of their commits. Your Git is going to call this other Git origin, by default.
We already saw that in any repository, we find the last commit of some branch by its branch name. So their Git—the one over on GitHub, or whatever—has some branch names:
...--o--o <-- master
\
o--o--o <-- develop
and so on. When you clone their repository, you get all of their commits, with their unique hash IDs that stay those hash IDs. But you don't get their branch names. Those are theirs. Your Git takes their names and changes them, so that you can have your own branch names.
The changes your Git makes to their branch names turn their names into your remote-tracking names. These names look like origin/master and origin/develop. These remember, in your repository, where their branch names were:
...--D--E <-- origin/master
\
F--G--H <-- origin/develop
For the last step of your git clone, your Git creates a new branch name, pointing to the same commit as one of their branch names. You can choose which branch this is but usually it's just master, so that you get:
...--D--E <-- master (HEAD), origin/master
\
F--G--H <-- origin/develop
If you now go making new commits, you get this:
I--J <-- master (HEAD)
/
...--D--E <-- origin/master
\
F--G--H <-- origin/develop
Now, suppose that they, whoever they are, manage to create two new commits on their master. Your Git does not have these commits yet, but you can get them.
You run:
git fetch origin
(or just git fetch, which defaults to origin). Your Git calls up their Git again. They tell your Git about their branch names (and other names) and your Git discovers that, gosh, there are new commits K-L to get from them. So your Git does, and then your Git updates your origin/master accordingly:
I--J <-- master (HEAD)
/
...--D--E--K--L <-- origin/master
\
F--G--H <-- origin/develop
(I've assumed here they did not add new commits to their develop, otherwise we'd have new commits on origin/develop now too.)
So, this is what git fetch is all about: your Git calls up some other Git, and gets new commits from that Git (if there are any to get) and then updates your remote-tracking names. After this git fetch you may have new commits. What if you want to use them?
To use their new commits after fetching, you need a second Git command
Let's say that you'd like to merge their work with your work, to create merge commit M in the usual way. You can now run:
git merge origin/master
This will make new merge commit M on its own, if it can, merging your J with their L, exactly as we saw above. It doesn't matter that commit L is found by a remote-tracking name instead of a branch name. Git doesn't care about names; Git cares about commits. So we get:
I--J--M <-- master (HEAD)
/ /
...--D--E--K--L <-- origin/master
\
F--G--H <-- origin/develop
This is where git pull comes in
The pull command just combines two commands into one:
- run
git fetch to get new commits from them; then
- run a second Git command to incorporate those new commits.
The default second command is git merge, so git fetch uses the commits that just came in to run a git merge. But git pull can run a deliberately limited kind of fetch, and doesn't just merge with any new commits from them. To know what to merge, git pull requires that you say what to use here.
The confusing part is that when you name what to use on the git pull command, you must use their branch names, even though your Git is going to work with your own remote-tracking names in a moment. So if you want to fetch from origin, then merge with what they call b2, you need:
git pull origin b2
This runs a limited kind of git fetch, then merges with whichever commit they're naming via their b2, that your Git names via your origin/b2. The missing slash here is because the first step—the git fetch—needs to know which Git to call up (the one at origin) and the second step needs to know which of their branch names to use.
Both of these two steps, git fetch and git merge, can fail. It's very unlikely for git fetch to fail (and git pull will stop if it does), but if you keep these as two separate commands, you can tell which one failed, if either one did. Moreover—and for me, much more important—you can look to see what git fetch fetched before you run git merge. And last, not so important once you know it, you'll realize that these are two entirely separate operations in Git: fetch gets commits; merge combines work.
It's safe to run git fetch any time, from any branch. Fetch just calls up another Git and gets commits from them. This does not touch anything you're doing right now. It's not so safe to run git merge any time: that merges something into your current branch, and you only have one current branch at any time. If you have lots of branches to update, you can git fetch and update all your remote-tracking names all at once, but then you have to, one by one, git checkout the branches you want updated, and git merge each one, with whichever commit you want to merge with—probably from the remote-tracking name for that branch, but because you can look, you can check first to see if you really do want that merge.
Sending commits to them
You now have commits I-J-M (with M having two parents, the first being J and the second being L) that they don't have. To send them your commits, you can use git push, providing they give you permission. (Note: these permissions are controlled by the hosting software, not by Git itself.) Running:
git push origin master
has your Git call up their Git, give them commits you have that they don't, that they'll need—in this case, I, J, and M—and then ask them to set their branch name. Note that you do not ask them to set a remote-tracking name. There are no remote-tracking names in this direction! You just ask them to set a branch name directly.
Sometimes, they'll accept this request. Sometimes they might refuse, because they've set up preventive barriers—maybe on specific branch names, and again, this is controlled by the hosting software—or because they just don't allow pushes at all. Or, they might refuse because you didn't merge, or didn't merge recently enough. Suppose they had the above, but while you were running git merge, someone else added another commit. If you run git fetch now, you'll get:
I--J--M <-- master (HEAD)
/ /
...--D--E--K--L--N <-- origin/master
\
F--G--H <-- origin/develop
which means that their master now names commit N, which didn't exist a moment ago. You might need to merge again, or maybe you want to remove your commit M entirely (which is a little tricky sometimes) and make a new merge O that incorporates N this time.
Package.json / Package-lock.json
https://www.jetbrains.com/help/idea/resolve-conflicts.html#CRLF_warning
https://www.jetbrains.com/help/idea/resolving-conflicts.html
Resolve conflicts
Last modified: 08 March 2021
Depending on your version control system, conflicts may arise in different situations.
When you work in a team, you may come across a situation when somebody commits changes to a file you are currently working on. If these changes do not overlap (that is, changes were made to different lines of code), the conflicting files are merged automatically. However, if the same lines were affected, your version control system cannot randomly pick one side over the other, and asks you to resolve the conflict.
Conflicts may also arise when merging, rebasing or cherry-picking branches.
Non-Distributed Version Control Systems
When you try to edit a file that has a newer version on the server, IntelliJ IDEA informs you about that, showing a message popup in the editor:

In this case, you should update your local version before changing the file, or merge changes later.
If you attempt to commit a file that has a newer repository version, the commit fails, and an error is displayed in the bottom right corner telling you that the file you are trying to commit is out of date.
The failed commit behavior is regulated by the Create changelist on failed commit list in the Version Control | Confirmation page of the Settings / Preferences dialog.
If you synchronize a file that already has local changes with a newer repository version committed by somebody else, a conflict occurs. The conflicting file gets the Merged with conflicts status. The file remains in the same changelist in the Local Changes view, but its name is highlighted in red. If the file is currently opened in the editor, the filename on the tab header is also highlighted in red.
Distributed Version Control Systems
Under distributed version control systems, such as Git and Mercurial, conflicts arise when a file you have committed locally has changes to the same lines of code as the latest upstream version and when you attempt to perform one of the following operations: pull, merge, rebase, cherry-pick, unstash, or apply patch.
If there are conflicts, these operations will fail and you will be prompted to accept the upstream version, prefer your version, or merge the changes manually:

The Conflicts dialog is triggered automatically when a conflict is detected on the Version Control level.
If you click Close in this dialog, or call a Git operation that leads to a merge conflict from command line, a Merge Conflicts node will appear in the Local Changes view with a link to resolve them:

IntelliJ IDEA provides a tool for resolving conflicts locally. This tool consists of three panes:
- The left page shows the read-only local copy
- The right pane shows the read-only version checked in to the repository
- The central pane shows a fully-functional editor where the results of merging and conflict resolving are displayed. Initially, the contents of this pane is the same as the base revision of the file, that is, the revision from which both conflicting versions are derived.

Resolve conflicts
Last modified: 08 March 2021
When you work in a team, you may come across a situation when somebody pushes changes to a file you are currently working on. If these changes do not overlap (that is, changes were made to different lines of code), the conflicting files are merged automatically. However, if the same lines were affected, Git cannot randomly pick one side over the other, and asks you to resolve the conflict.
In Git, conflicts may arise when you attempt to perform one of the following operations: pull, merge, rebase, cherry-pick, unstash changes or apply a patch. If there are conflicts, these operations will fail, and you will be prompted to accept the upstream version, prefer your version, or merge the changes:

The Conflicts dialog is triggered automatically when a conflict is detected on the Git level.
If you click Close in this dialog, or call a Git operation that leads to a merge conflict from command line, a Merge Conflicts node will appear in the Local Changes view with a link to resolve them:

IntelliJ IDEA provides a tool for resolving conflicts locally. This tool consists of three panes:
- The left pane shows the read-only local copy
- The right pane shows the read-only version checked in to the repository.
- The central pane is a fully-functional editor where the results of resolving conflicts are displayed. Initially, the contents of this pane are the same as the base revision of the file, that is, the revision from which both conflicting versions are derived.

Resolve conflicts
Click Merge in the Conflicts dialog, the Resolve link in the Local Changes view, or select the conflicting file in the editor and choose VCS | Git | Resolve Conflicts from the main menu.
To automatically merge all non-conflicting changes, click
(Apply All Non-Conflicting Changes) on the toolbar. You can also use the
(Apply Non-Conflicting Changes from the Left Side) and
(Apply Non-Conflicting Changes from the Right Side) to merge non-conflicting changes from the left/right parts of the dialog respectively.
To resolve a conflict, you need to select which action to apply (accept
or ignore
) to the left (local) and the right (repository) version, and check the resulting code in the central pane:

You can also right-click a highlighted conflict in the central pane and use the commands from the context menu. The Resolve using Left and Resolve using Right commands provide a shortcut to accepting changes from one side and ignoring them from the other side respectively:

For simple conflicts (for example, if the beginning and the end of the same line have been modified in different file revisions), the Resolve simple conflicts
button that allows merging the changes in one click becomes available.

Such conflicts are not resolved with the Apply All Non-Conflicting Changes action since you must make sure that they are resolved properly.
Note that the central pane is a fully-functional editor, so you can make changes to the resulting code directly in this dialog.
It may also be useful to compare different versions to resolve a conflict. Use the
toolbar button to invoke the list of options. Note that Base refers to the file version that the local and the repository versions originated from (initially displayed in the middle pane), while Middle refers to the resulting version.
Review merge results in the central pane and click Apply.
Productivity tips
Apply non-conflicting changes automatically
You can configure IntelliJ IDEA to always apply non-conflicting changes automatically instead of telling it to do so from the Merge dialog. To do this, select the Automatically apply non-conflicting changes option on the Tools | Diff Merge page of the IDE settings ⌘,.
Manage changes in the central pane
You can manage changes in the central pane using the toolbar that appears when you hover the mouse cursor over a change marker in the gutter, and then click it. The toolbar is displayed together with a frame showing the previous contents of the modified line:
For example, when there are multiple non-conflicting changes, and you only need to skip one or two of them, it's easier to apply all of them simultaneously using the Apply all non-conflicting changes action, and then undo the unwanted ones using the Revert action from this toolbar.
Quite often, people working in a team and contributing to the same repository use different operating systems. This may result in problems with line ending, because Unix, Linux and MacOS us LF, and Windows uses CRLF to mark the end of a line.
IntelliJ IDEA displays the discrepancies in line endings in the Differences Viewer, so you can fix them manually. If you want Git to solve such conflicts automatically, you need to set the core.autocrlf attribute to true on Windows and to input on Linux and MacOS (for more details, see Dealing with line endings). You can change the configuration manually by running git config --global core.autocrlf true on Windows or git config --global core.autocrlf input on Linux and macOS.
However, IntelliJ IDEA can automatically analyze your configuration, warn you if you are about to commit CRLF into a remote repository, and suggest setting the core.autocrlf setting to true or input depending on your operating system.
To enable smart handling of LF and CRLF line separators, open the Settings/Preferences dialog ⌘,, and select the Version Control | Git node on the left. Enable the Warn if CRLF line separators are about to be committed option.
After you have enabled this option, IntelliJ IDEA will display the Line Separators Warning Dialog each time you are about to commit a file with CRLF separators, unless you have set any related Git attributes in the affected file (in this case, IntelliJ IDEA supposes that you clearly understand what you are doing and excludes this file from analysis).
In the Line Separators Warning Dialog, click one of the following:
- Commit As Is to ignore the warning and commit a file with
CRFL separators.
- Fix and Commit to have the
core.autocrlf attribute set to true or input depending on your operating system. As a result, CRLF line separators will be replaced with LF before the commit.
If, at a later time, you need to review how exactly conflicts were resolved during a merge, you can locate the required merge commit in the Log tab of the Git tool window ⌘9, select a file with conflicts in the Commit Details pane in the right, and click <
or press ⌘D (see Review how changes were merged for details).
NPM creates a new package-lock.json – do you commits?
(e.g. my version of silvermine player had to be updated to match up with the updated package.json file from stage)
Yes, package-lock.json is intended to be checked into source control. If you're using npm 5+, you may see this notice on the command line: created a lockfile as package-lock.json. You should commit this file. According to npm help package-lock.json:
package-lock.json is automatically generated for any operations where npm modifies either the node_modules tree, or package.json. It describes the exact tree that was generated, such that subsequent installs are able to generate identical trees, regardless of intermediate dependency updates.
This file is intended to be committed into source repositories, and serves various purposes:
- Describe a single representation of a dependency tree such that teammates, deployments, and continuous integration are guaranteed to install exactly the same dependencies.
- Provide a facility for users to "time-travel" to previous states of
node_modules without having to commit the directory itself.
- To facilitate greater visibility of tree changes through readable source control diffs.
- And optimize the installation process by allowing npm to skip repeated metadata resolutions for previously-installed packages.
One key detail about package-lock.json is that it cannot be published, and it will be ignored if found in any place other than the toplevel package. It shares a format with npm-shrinkwrap.json, which is essentially the same file, but allows publication. This is not recommended unless deploying a CLI tool or otherwise using the publication process for producing production packages.
If both package-lock.json and npm-shrinkwrap.json are present in the root of a package, package-lock.json will be completely ignored.
If software did not resolve package.json conflicts
Package.json – ALL INFO
https://docs.npmjs.com/cli/v6/configuring-npm/package-json
https://docs.npmjs.com/cli/v6/configuring-npm/package-locks
Resolving lockfile conflicts
Occasionally, two separate npm install will create package locks that cause merge conflicts in source control systems. As of npm@5.7.0, these conflicts can be resolved by manually fixing any package.json conflicts, and then running npm install [--package-lock-only] again. npm will automatically resolve any conflicts for you and write a merged package lock that includes all the dependencies from both branches in a reasonable tree. If --package-lock-only is provided, it will do this without also modifying your local node_modules/.
To make this process seamless on git, consider installing npm-merge-driver, which will teach git how to do this itself without any user interaction. In short: $ npx npm-merge-driver install -g will let you do this, and even works with pre-npm@5.7.0 versions of npm 5, albeit a bit more noisily. Note that if package.json itself conflicts, you will have to resolve that by hand and run npm install manually, even with the merge driver.
package-locks
An explanation of npm lockfiles
Table of contents
Description
Conceptually, the "input" to npm install is a package.json, while its "output" is a fully-formed node_modules tree: a representation of the dependencies you declared. In an ideal world, npm would work like a pure function: the same package.json should produce the exact same node_modules tree, any time. In some cases, this is indeed true. But in many others, npm is unable to do this. There are multiple reasons for this:
- different versions of npm (or other package managers) may have been used to install a package, each using slightly different installation algorithms.
- a new version of a direct semver-range package may have been published since the last time your packages were installed, and thus a newer version will be used.
- A dependency of one of your dependencies may have published a new version, which will update even if you used pinned dependency specifiers (
1.2.3 instead of ^1.2.3)
- The registry you installed from is no longer available, or allows mutation of versions (unlike the primary npm registry), and a different version of a package exists under the same version number now.
As an example, consider package A:
{
"name": "A",
"version": "0.1.0",
"dependencies": {
"B": "<0.1.0"
}
}
package B:
{
"name": "B",
"version": "0.0.1",
"dependencies": {
"C": "<0.1.0"
}
}
and package C:
{
"name": "C",
"version": "0.0.1"
}
If these are the only versions of A, B, and C available in the registry, then a normal npm install A will install:
A@0.1.0
`-- B@0.0.1
`-- C@0.0.1
However, if B@0.0.2 is published, then a fresh npm install A will install:
A@0.1.0
`-- B@0.0.2
`-- C@0.0.1
assuming the new version did not modify B's dependencies. Of course, the new version of B could include a new version of C and any number of new dependencies. If such changes are undesirable, the author of A could specify a dependency on B@0.0.1. However, if A's author and B's author are not the same person, there's no way for A's author to say that he or she does not want to pull in newly published versions of C when B hasn't changed at all.
To prevent this potential issue, npm uses package-lock.json or, if present, npm-shrinkwrap.json. These files are called package locks, or lockfiles.
Whenever you run npm install, npm generates or updates your package lock, which will look something like this:
{
"name": "A",
"version": "0.1.0",
...metadata fields...
"dependencies": {
"B": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/B/-/B-0.0.1.tgz",
"integrity": "sha512-DeAdb33F+"
"dependencies": {
"C": {
"version": "git://github.com/org/C.git#5c380ae319fc4efe9e7f2d9c78b0faa588fd99b4"
}
}
}
}
}
This file describes an exact, and more importantly reproducible node_modules tree. Once it's present, any future installation will base its work off this file, instead of recalculating dependency versions off package.json.
The presence of a package lock changes the installation behavior such that:
- The module tree described by the package lock is reproduced. This means reproducing the structure described in the file, using the specific files referenced in "resolved" if available, falling back to normal package resolution using "version" if one isn't.
- The tree is walked and any missing dependencies are installed in the usual fashion.
If preshrinkwrap, shrinkwrap or postshrinkwrap are in the scripts property of the package.json, they will be executed in order. preshrinkwrap and shrinkwrap are executed before the shrinkwrap, postshrinkwrap is executed afterwards. These scripts run for both package-lock.json and npm-shrinkwrap.json. For example to run some postprocessing on the generated file:
"scripts": {
"postshrinkwrap": "json -I -e \"this.myMetadata = $MY_APP_METADATA\""
}
Using locked packages
Using a locked package is no different than using any package without a package lock: any commands that update node_modules and/or package.json's dependencies will automatically sync the existing lockfile. This includes npm install, npm rm, npm update, etc. To prevent this update from happening, you can use the --no-save option to prevent saving altogether, or --no-shrinkwrap to allow package.json to be updated while leaving package-lock.json or npm-shrinkwrap.json intact.
It is highly recommended you commit the generated package lock to source control: this will allow anyone else on your team, your deployments, your CI/continuous integration, and anyone else who runs npm install in your package source to get the exact same dependency tree that you were developing on. Additionally, the diffs from these changes are human-readable and will inform you of any changes npm has made to your node_modules, so you can notice if any transitive dependencies were updated, hoisted, etc.
Resolving lockfile conflicts
Occasionally, two separate npm install will create package locks that cause merge conflicts in source control systems. As of npm@5.7.0, these conflicts can be resolved by manually fixing any package.json conflicts, and then running npm install [--package-lock-only] again. npm will automatically resolve any conflicts for you and write a merged package lock that includes all the dependencies from both branches in a reasonable tree. If --package-lock-only is provided, it will do this without also modifying your local node_modules/.
To make this process seamless on git, consider installing npm-merge-driver, which will teach git how to do this itself without any user interaction. In short: $ npx npm-merge-driver install -g will let you do this, and even works with pre-npm@5.7.0 versions of npm 5, albeit a bit more noisily. Note that if package.json itself conflicts, you will have to resolve that by hand and run npm install manually, even with the merge driver.
See Also
DO NOT – Delete `package-lock.json` to Resolve Conflicts quickly
Yes it can have bad side effects, maybe not very often but for example you can have in package.json “moduleX”: “^1.0.0” and you used to have “moduleX”: “1.0.0” in package-lock.json.
By deleting package-lock.json and running npm install you could be updating to version 1.0.999 of moduleX without knowing about it and maybe they have created a bug or done a backwards breaking change (not following semantic versioning).
Anyway there is already a standard solution for it.
Fix the conflict inside package.json
Run: npm install –package-lock-only
https://docs.npmjs.com/cli/v7/configuring-npm/package-locks#resolving-lockfile-conflicts
package-lock.json – role
It stores an exact, versioned dependency tree rather than using starred versioning like package.json itself (e.g. 1.0.*). This means you can guarantee the dependencies for other developers or prod releases, etc. It also has a mechanism to lock the tree but generally will regenerate if package.json changes.
From the npm docs:
package-lock.json is automatically generated for any operations where npm modifies either the node_modules tree, or package.json. It describes the exact tree that was generated, such that subsequent installs are able to generate identical trees, regardless of intermediate dependency updates.
This file is intended to be committed into source repositories, and serves various purposes:
Describe a single representation of a dependency tree such that teammates, deployments, and continuous integration are guaranteed to install exactly the same dependencies.
Provide a facility for users to “time-travel” to previous states of node_modules without having to commit the directory itself.
To facilitate greater visibility of tree changes through readable source control diffs.
And optimize the installation process by allowing npm to skip repeated metadata resolutions for previously-installed packages.”
To answer jrahhali’s question below about just using the package.json with exact version numbers. Bear in mind that your package.json contains only your direct dependencies, not the dependencies of your dependencies (sometimes called nested dependencies). This means with the standard package.json you can’t control the versions of those nested dependencies, referencing them directly or as peer dependencies won’t help as you also don’t control the version tolerance that your direct dependencies define for these nested dependencies.
Even if you lock down the versions of your direct dependencies you cannot 100% guarantee that your full dependency tree will be identical every time. Secondly you might want to allow non-breaking changes (based on semantic versioning) of your direct dependencies which gives you even less control of nested dependencies plus you again can’t guarantee that your direct dependencies won’t at some point break semantic versioning rules themselves.
The solution to all this is the lock file which as described above locks in the versions of the full dependency tree. This allows you to guarantee your dependency tree for other developers or for releases whilst still allowing testing of new dependency versions (direct or indirect) using your standard package.json.
NB. The previous shrink wrap json did pretty much the same thing but the lock file renames it so that it’s function is clearer. If there’s already a shrink wrap file in the project then this will be used instead of any lock file.
Solving conflicts in package-lock.json
https://tkdodo.eu/blog/solving-conflicts-in-package-lock-json
One thing that can be costly when done wrong is solving conflicts in generated files, like package-lock.json. It usually happens when two branches add or update a dependency. The result of package-lock then changes, and whoever gets their PR merged to main first is the lucky one who avoided those conflicts. It's almost like a race.
So here you are, updating your PR with the base branch, and git shows you this huge amount of conflicts in package-lock.json. The conflicts in package.json are usually easily solved (if there even are any), so I think it is tempting to just delete package-lock.json and run npm install. After all, this will give you a brand new package-lock.json, which you can happily commit.
Why you should never delete package-lock.json
When you install a dependency for the first time, it is usually automatically added to your dependencies or devDependencies with ^version, which means "compatible with version, according to semver". You can try out what that means here.
Enter, for example, lodash as the package and ^4.2.1 as version, and you will see that you can get anything from 4.2.1 to 4.17.20 (the latest version)

This is where package-lock.json comes into play. Upon installing, it will "lock" you in on the version that you just installed. So if 4.2.1 is the latest version at the moment of your install, this version will be written to package-lock and will, from there on, always be installed. Even if newer versions come out that are theoretically compatible with it.
This is important because it guarantees that every developer in the team will have the same version on their machine, and it is equally important for CI/CD. I would not want to ship a newer version to production than we tested with, even if it's just a patch version.
So when you delete package-lock.json, all those consistency goes out the window. Every node_module you depend on will be updated to the latest version it is theoretically compatible with. This means no major changes, but minors and patches. I believe this is bad for three reasons:
It trusts that everyone strictly adheres to semantic versioning, and I sincerely doubt that this is the case. There is also no way to enforce this.
Major version zero is exempt from the rules of semantic versioning. From
the semver spec
:
Major version zero (0.y.z) is for initial development. Anything MAY change at any time. The public API SHOULD NOT be considered stable.
Have a look at your package-lock.json and count how many dependencies with major version 0 you have. For this blog (made with gatsby) I have 362!
- This also applies to transitive dependencies. So even if you are using strict versions (without the
^), the libraries you are using do not.
If you delete package-lock.json now from any one of your projects and run npm install again, it will most certainly look completely different.
Will your app be fine? Maybe, maybe not. No one can tell. For me, this would usually mean: "regression test everything", which is certainly not what I have in mind when I am just solving a conflict.
What you can do instead
My usual approach was the following:
- Solve the conflicts in package.json
- Take package-lock.json from the base branch
- run npm install again
This will then just re-install whatever changes we made in our branch. However, I recently learned about and even easier way:
npm can automatically detect conflicts in package-lock.json and resolve them for us. From the npm docs:
Occasionally, two separate npm install will create package locks that cause merge conflicts in source control systems. As of npm@5.7.0, these conflicts can be resolved by manually fixing any package.json conflicts, and then running npm install [–package-lock-only] again. npm will automatically resolve any conflicts for you and write a merged package lock that includes all the dependencies from both branches in a reasonable tree. If –package-lock-only is provided, it will do this without also modifying your local node_modules/.
This means that we can just keep the conflicts in the lock file. All we have to do is get package.json right, and npm will do the rest for us 🎉.
I wish I had known this sooner – it would've saved me some trouble.