# WORKING ON A FEATURE ## Creating new feature branch out of the master/development branch 1. Create branch out of master ```git git checkout master git checkout -b yourName-projectName-taskName ``` 2. Adding appropriate prefix Also, you should add appropriate prefix before the branch name feature/.. fix/.. 3. Pushing the new branch to the remote origin ```git git push -u origin prefix/yourName-projectName-taskName ``` ## Squashing commits before rebase ```git git rebase -i {hash} # to squash all commits, where the oldest one is {hash} ``` ## Rebasing parent branch ```git git pull --rebase -i origin branchName # to get new changes from the remote repo and rebase ``` Resolve if any conflicts, and continue ```git git rebase --continue ``` Force push changes ```git git push -f ``` ## Merging back into parent branch ```git git checkout master git merge -X theirs featureBranch ``` # EXPLAINED GIT COMMANDS WHEN WORKING ON A NEW BRANCH Two options will be reviewed: - **Rebase** - applies all of the parent (or other specified) branch commits onto your branch. This moves your branch to begin on the tip of the rebased branch, effectively incorporating all of the new commits in specified branch. Use it when you are working on a feature, and needs to get fresh changes occasionally. - **Merge** - merges your changes into the specified branch, also it creates new merge commit. Use it when you are done with changes, and need to merge your branch back to the parent branch. **NOTE**: You should only merge your branch, when you are done with all changes, and it is up-to-date with the branch you are merging. ### PROBLEM ### Let's say we have the following situation: 1. We create 'feature-x' branch out of 'master' branch 2. We did 30 commits that modifies file1, file2, etc. 2. Other developers also made 30 commits on 'master' branch modifying file1, file2, etc. 6. You will now want to update your branch with fresh commits from master in order to continue working on a feature. What will happen is, you will need to review every conflict in those 30 commits, where the similar things were changed. ### SOLUTION ### **Squashing** You will need to squash all commits made since you created branch, in order to get the new updates. Always use interactive squashing, because it gives you the most control. You can choose what to do with the specific commit: squash, delete, pick, fixup, etc. In simple cases, it is enough to give squash (s) to every commit, except the first one leave it on pick (p). You got few **options** when using rebase: - Give hash value of the commit if you want to rebase every commit since that commit, except the given commit - Give HEAD~2 if you want to rebase last 2 commits. ```git git rebase -i {option} # to squash commits ``` **Rebasing** You will need to rebase on a branch (usually parent - master) ```git git rebase branch # rebase if local version of the branch is up-to-date git pull --rebase -i origin branch # to get new changes from the remote repo and rebase ``` ![rebase-interactive](/uploads/-/system/personal_snippet/1/30a6d66536b06dc548cfd5e5f874a4f0/rebase-interactive.png "Interactive rebasing. Click to enlarge") **Update** After you finished with rebasing, force update the remote repository, since you will have different commmits locally and remotely ```git git push -f ``` *BE AWARE*: Don't do it if you are not sure what you are actually doing. This overrides the remote branch with your local changes. ### Resolve conflicts (automatically) If you rebase a branch feature-x against master i.e. running: git rebase master while on branch feature-x, during rebasing, ours refers to master and theirs to feature-x. - Rebase preferring current branch (feature-x) changes merge during conflicts ```git git rebase -Xtheirs master ``` After this step, always rebuild the code, to see if something wrong was done. ### THEIRS AND OURS (Merge vs Rebase) Theirs and Ours behave differrently in merge than in rebase, they are reversed due to the differences on how git rebase and git merge operate assuming feature-x is our current version ```git git rebase -Xtheirs feature-x # <- ours: feature-x, theirs: master git merge -Xtheirs feature-x # <- ours: master, theirs: feature-x git merge -Xours origin/master ``` ## THE GOLDEN RULE OF REBASING Never use it on public branches (master, development, staging, production, ...), use only on your emerged branch! If you do git rebase feature-x during on master branch, the flow will look like this: ![alt text](http://www.programmergirl.com/wp-content/uploads/2018/06/GitMerge1.png "Logo Title Text 2") In this situation, only you will have ## RESET AND REVERT COMMITS ```git git revert {hash} git reset # Reverts and unstage changes git reset --soft HEAD^6 # Does not touch the index file or the working tree at all git reset --soft tags/v1.0.1 git reset --hard # Resets the index and working tree. Any changes to tracked files in the working tree since are discarded. git reset -- file # Suppose you have added a file to your index, but later decide you do not want to add it to your commit. You can remove the file from the index while keeping your changes with git reset. <a href="https://git-scm.com/docs/git-reset#Documentation/git-reset.txt-Resetasinglefileintheindex" target="_blank" rel="noopener">Details</a>. ``` If you accidentially commit something, or you were not finished doing it, you can do it in two ways: 1. **Hard reset** - removes commits altogether with files changed, they are gone. ```git git reset --hard OPTION ``` It is preferably if you do git branch feature-y-copy before doing hard reset, in order to keep commits. Then do git push -f to force push local changes 2. **Reset (soft)** - points HEAD to the commit(s) and returns changes from commit(s) in the stage so you can change and commit with different message etc. ```git git reset OPTION ``` 3. **Revert** - this will create another commit with deleted changes. ```git git revert OPTION ``` **OPTIONS:** HEAD^ - last commit HEAD~X - last X commits {hash} - every commit after this {hash} commit # Q&A 1. Why not merge to get new changes from parent branch? - Because it will create new commit every merge, and history log will look nasty. With rebase, history will look clean and pretty. 2. I did a nasty mistake, and everything went wrong. What to do now? - Use reflog. git reflog (--date=iso to get detailed timestamps) is reference log, that keeps log of every step done via git command. It creates hash value for every step or sub-step done with git. Just checkout the last working hash value and you are good to go. ```git git checkout {hash} ``` 3. Discarding local changes and checkout remote branch ```git git reset --hard origin/branchName ``` 4. Detached state. What now? ```git git push --origin <branch> ``` # TO BE CONTINUED...