# Git Merges and You Git needs to know to to combine code, and there are different ways git can combine code, each are useful in different situations and have their own protocols. Sometimes git does not know how to automatically combine the code for us, and that means a `merge conflict` is occuring. We must help git sort out a merge conflict, if one is to arise during a merge. ![go on, git](https://media.giphy.com/media/j5Qgf8rf2VYnoWH3SY/giphy.gif) ## The Big Three There are three types of merges that are important to know: * `fast forward` -- when two branches can be easily combined, a fast-forward occurs. Git prefers to fastforward when new code is pulled from a remote to a local. Fast forwards cannot happen if a merge conflict is present. * `merge` -- the good old fashioned merge. Creates a new commit with a message that describes why the code is being combined. This is the prefered method when merging a new feature into software that is in production. If a merge conflict occurs, the files must be edited in every spot where git does not know how to combine the code, and then the files must be staged with a `git add ...` and a commit must occur with a `git commit ...`. Code that is combined with a git merge retains information about both of the branches being combined, along with all of the commits from both branches * `git rebase` -- two branches are combined, but the history of the branch that is being merged in is re-written to apear like it occured on the current branch. Git prefers to rebase when pulling code from a remote, if a `fast forward` cannot occur. No merge commit is created during a rebase. This is useful to not have git commit history cluttered up with branch and commit information everytime the team needs to pull down updates from their other team members. Git rebases can handle conflicts too, but with a different process than a `git merge`. For a rebase conflict, files are edited to no longer conflict, and then statged with a `git add ...`. After all conflicts have be fixed, the command `git rebase --continue` is used. This is to avoid making a commit during the rebasing process. #### TODO: Add Visualizations the three merges w git commit histories examples ## Commands to make branches If a branch does not exist, it must be created before you can checkout to it. * `git branch < new branch name >` -- creates a new branch with the name `< new branch name >` * `git checkout < branch name >` -- switches to `< branch name >` * `git checkout -b < new branch name >` -- creates and switches to `< new branch name >` * `git branch` -- lists all local branchs (press `q` to exit) * `git branch -a` -- lists all local and remote branches (press `q` to exit) **_NOTE: Remember to always commit on your current branch before checking out to a new branch_** ## Commands to Merge Branches ![git merge](https://i.giphy.com/media/cFkiFMDg3iFoI/giphy.webp) You can tell git to merge a branch into your current branch: * if you are on the `main` branch and you run `git merge feature`, git will merge `feature` into `main` * if you are on `main` branch and you run `git rebase feature`, git will rebase `feature` into `main` One thing to note is that git will open a commit message file by default when making a merge. It is possible to supply a commit message with the `-m` flag when merging, like a commit: `git merge -m 'your commit mesage' feature` The defualt editor git will open on many *nix systems is [vim](https://stackoverflow.com/a/11828573). You can configure git to use vscode as the defualt editor by running `git config --global core.editor "code --wait"` so the commit message file opens in vscode. ## Navigating Merge Conflicts When a merge conflict occurs in Git, it means that there are changes in the same lines of code in both the branch you are merging and the branch you are merging into. To navigate a Git merge with a conflict, you can follow these steps. ![types of headaches meme](https://i.imgur.com/yk5rf13.png) It's always a good practice to review the changes on both branches before resolving the conflict, and to communicate with your other team members whose code hase created a conflict with your own. When git has a merge conflict you should always first identify the files with merge conflicts by running the command `git status` in the command line. This will show you a list of files that have merge conflicts. In this example, there is a merge conflict in app.js: ```bash On branch main You have unmerged paths. (fix conflicts and run "git commit") (use "git merge --abort" to abort the merge) Unmerged paths: (use "git add <file>..." to mark resolution) both modified: app.js no changes added to commit (use "git add" and/or "git commit -a") ``` If this where a rebase, the output would look like this: ```bash interactive rebase in progress; onto db7a4dd Last command done (1 command done): pick a4fa706 updates examp on main No commands remaining. You are currently rebasing branch 'main' on 'db7a4dd'. (fix conflicts and then run "git rebase --continue") (use "git rebase --skip" to skip this patch) (use "git rebase --abort" to check out the original branch) Unmerged paths: (use "git restore --staged <file>..." to unstage) (use "git add <file>..." to mark resolution) both modified: app.js no changes added to commit (use "git add" and/or "git commit -a") ``` Look at each file, and decide which changes you want to keep and which changes you want to discard. You can manually edit the file to keep the changes that you want and remove the changes that you don't want. The file need to be edited to resolve the conflict. Git will always the merge conflicts will be inbetween the text `<<<<<<< HEAD`, `=======` and `>>>>>>> < incoming branch name >`, for example: ```javascript= function main() { console.log("Hello, world!") <<<<<<< HEAD console.log("This is the main branch.") ======= console.log("This is the feature branch.") >>>>>>> feature } ``` After editing the code and removing the markers, you need to `git add` the file with the conflict to stage it. Your next step depends on if you are rebasing or merging: merges us `git commit` rebases use `git rebase --continue` #### TODO: add detailed instructions on how to replicate merge conflicts and rebase conflicts ### Standard Merge Conflicts If you experience a a conflict while merging, you must update all merge conflicts and create commit to complete the merge. If a merge conflict has occured, git will output a message similar to this: ```bash Auto-merging app.js CONFLICT (content): Merge conflict in app.js Automatic merge failed; fix conflicts and then commit the result. ``` * `git status` - to see which files have merge conflicts * Edit the files that have conflicts and remove the conflict markers * `git add` - to stage the changes * `git commit -m 'resolving merge'` - to complete the merge ### Rebase Merge Conflicts In contrast to merges, we do not create commits when resolving rebase conflicts, as the goal of the rebase is to not clutter up the git commit history, instead you: If a merge conflict occurs during a rebase, git will output something similar to this: ```bash Auto-merging app.js CONFLICT (content): Merge conflict in app.js error: could not apply a4fa706... commit message on main hint: Resolve all conflicts manually, mark them as resolved with hint: "git add/rm <conflicted_files>", then run "git rebase --continue". hint: You can instead skip this commit: run "git rebase --skip". hint: To abort and get back to the state before "git rebase", run "git rebase --abort". Could not apply a4fa706... commit message on main ``` * `git status` - to see which files have merge conflicts * Edit the files that have conflicts and remove the conflict markers * `git add` - to stage the changes * `git rebase --continue` - to continue the rebase with the resolved conflicts. Typicially this will end the rebase, but if git has another conflict you will have to start at the top again and repeat the process. one of the biggest hints that you are in the middle of a rebase would be the branch you are currently on is a tempory hash, and not `main` or a `feature`: ![repo currently in a rebase](https://i.imgur.com/DckBnqQ.png) ## The Process of Pulling When you perform a `git pull`, two actions occur: a `git fetch` and a`git merge`, `git fast-forward` or `git rebase` depending on your configuration. The` git fetch` action retrieves the latest commits from a remote repository and updates the local copy of the remote branches. This does not change the local branches, but it does make the latest commits from the remote available for merging or rebasing. The` git merge`, or `git rebase` action is then used to integrate the changes from the remote branch into the local branch. For example if you type `git pull upstream main` into your terminal, git does the following actions: 1. git checks the repo's remote configuration for a url named 'upstream' 1. if an url named 'upstream' is found, git runs `git fetch upstream main` using that url, which downloads the main branch 1. git checks if the branch it just downloaded, `upstream/main` can be combined with your current branch branch with a fast-forward. If it can, git fast forwards and then the proccess is complete. 1. If git cannot fastforward, if checks your config for your preferred way of combining branches during a pull, which can be either a `rebase` or a `merge`. 1. If git combine the branch it downloaded, `upstream/main` without a merge confilict, it does so using your defualt merge stretegy (merge or rebase) 1. If there is a merge conflict, git starts the merge conflict process for your defualt merge strategy (merge or rebase) ### Forcing git to use a specific type of merge when pulling You can break the pull process down into theses steps, if you want to specify how to merge code when pulling * `git fetch <remote> <branch>` where `<remote>` is the repo on github to pull from and `<branch>` is the branch on github you wish to get * `git <merge type> <remote>/<branch>` where `<merge type>` is either `rebase` or `merge` and `<remote>/<branch>` is the github repo and branch with a slash, such as `upstream/main` ### Pulling a different branch than the one you are on In many situations you may want to pull a branch that you are not currently working on, and then merge it into your current branch. Example: The git manager tells the team that there is a new feature just added upstream, and its on the main branch. Everyone needs to pull it down. You are currently working on a feature branch, `navbar`. How do you pull down the new code into your feature branch? first, you will `upsteam/main` to your local `main`: * `git pull upstream main` your `main` branch now has all of the code from `upstream/main`. How do you get that code onto your feature branch? You can either merger or rebase it in: * `git merge -m "merging updates from upstream/main to navbar" main` -- merges your local main branch into the branch you currently are on (navbar) and the `-m` defines what the merge's commit message will be **_OR_** you could do this (_you do not need to do both_): * `git rebase main` -- rebases your local main branch into the feature branch you currently are on (navber) ###### tags: `lessons`