So this is a continuation of the previous git article I wrote. It finished on the command
I will focus on problems that you may run into and how they can be circumvented and solved using git. Hopefully by then end of this, you will no longer be scared of screwing up with git (and stop making 20 million backups of your code). Since git is language/software independent, all the things you learn can be used with whatever IDE/language you use and for my own convenience’s sake, I will use Xcode.
Conflicts arise in code when 2 different people make a change to the same line in code. The person who pushes to the remote first is lucky since they don’t have to resolve conflicts but the person taking the pull does. Conflicts can be quite complex or simple depending on how the code is laid out. So this can occur if people are working on different branches and try to merge the code or even if they are working on the same branch. The key criteria, like I mentioned before is making changes to the same line of code.
The easiest way to avoid conflicts is keep your team members upto date about what you will be working on and to take regular pulls from the stable release. The earlier you detect conflicts the less you have to deal with later. Having 89 conflicts is way more intimidating than just 3. Communication is an important part not only to avoid them but resolving as well. Most of the time the change is that your team member maybe changed the indentation or added a comment in which case, if you want to, just ignore their code!
Heck, if i talk about Xcode, the IDE does this annoying thing (or used to) that if you open up a file, it will change some settings related to the layout (never really found out the reason why). When another member who actually had to work on the layout does his stuff and we tried to merge the code, it would show conflicts.
I’ve heard of a myth saying that you should work on different branches to avoid conflicts, but this is not the case. I’ll agree that you won’t get conflicts regularly but if you have made changes to the same line then you will get conflicts when you merge to the main code.
This is how a conflict typically looks like:
The code between HEAD and ======= refers to where the code in the current branch is. The current branch is the branch in which we are merging code into from another branch. The code you are merging into yours is also referred to as the Tail. Whenever you run git status, you will see something called a HEAD. That basically means where the git pointer to your code is and appropriately, the same convention is used here. Now to resolve the conflict, you can do a couple of things.
- Delete your code between HEAD and ====== (including these lines), to remove your code.
- Delete the pulled/merged code between ====== and temp (including these lines), to remove other code.
- Delete the <<<< HEAD, ======= and >>>>> temp lines only to keep both instances of the code.
This is where you have to make a call, which code to keep or if you need to keep both instances.
Note: The case I highlighted above is merging. But it may arise as well if someone pushes into the same branch and you take a pull, provided changes to the same line are made. In this case instead of temp there will be the commit id (alphanumeric string) of the commit causing the conflict with your code. But everything else will remain the same
What to do if you make a mistake
You may make a mistake that deletes a block of code and you need to have it re-added and don’t want to manually copy paste it again. Just make sure you do not push anything to the remote after resolving conflicts and if anyone takes a pull if you do that, their code will be updated with whatever resolution you made. What you should do:
After the command, you will get some output that kinda looks like the following image:
Get an output like this. What you need to do is copy the commit id (just the alphanumeric string) and run the following command:
git reset --hard commit_id_to_revert_to
This informs your local copy to push the git pointer or head back to the commit you pass the id of, making it as if the conflict never happened. You can now take a pull again to retry! If you don’t reset your code, git won’t allow you to take a pull or do a merge again, informing you that there is nothing to pull, since the git pointer points to the latest pull.
I know this is not the best solution if you have 10 conflicts and you fix 9 of them and this happens on the last one. But this is the most sure fire way I know of to make sure no code is lost (which imo is quite worse than spending some extra time in resolving conflicts).
To summarise, here is the sequence of commands
//Perform XYZ tasks and commit whatever you didgit add -A
git commit -m "Commit before conflict"
git pull origin master//conflicts appears1. //resolve conflict and if no problem happens:
git add add -A
git commit -m "Conflict resolved"
git push origin master2. //resolve conflict but code doesn't work as expected
git reset --hard id_of_commit_before_conflict
//try again till 1. happens
In the previous section, we talked about git reset as well. What this command does is to move your code back to the state it was in when you committed the code, based on the commit id you pass it. It has two noteworthy arguments, — soft and — hard.
git reset --soft 3947sdfhdnckx90fsd80sf8d
Now let us say you have committed code with ids starting from 1–10. Naturally your git pointer or head is at the id 10. If you do
git reset --soft 5
Then although your git pointer moves back to 5. The changes are not removed from the code. They are still present but are pending commit. If you do git status at this point, it will show the code between commits 5–10 that was present as modifications in the relevant files and that they are waiting to be committed.
git reset --hard 5
If you run reset with — hard, it reverts the code back as well and would have removed all changes done between commits 5–10.
Another silly mistake I have done more times than I should have and will probably keep doing, is that I forget which branch I am on and accidentally commit code to it. Now since I don’t want development tasks on the master branch, I will have to remove the commit from git’s tracking history. You can use git reset again to help overcome this issue.
//go on wrong branch
git checkout master
git add -A
git commit -m "Accidental commit"
//below is the commit where the code present in master is supposed //to be till
git reset --soft commit_id_commit_before_accidental_commitgit stash //don't worry. Your code isn't lost
git checkout development //or branch you want
git stash apply //pops latest stashed changes and applies them
git commit -m "Correct commit on correct branch"//be happy
Now the above sequence of events will work as long as you haven’t pushed code to the remote. If you have well then you might have overwrite your changes on the remote using the — force flag. Use — force with extreme caution as it will overwrite all changes on the remote.
//in case of pushing changes to remote
git checkout master
git add -A
git commit -m "Accidental commit"
git push origin master//WHOOPS, WRONG BRANCH
git reset --soft commit_id_before_accidental_commit
git push origin master --force //re-update the remote with the //correct commit. MAKE SURE no team member has pushed his code after //taking a pull as that complicates stuff.git checkout development
git stash apply//be happy
So this is it. Both the GIT related guides that I have written is all I have ever really needed to solve 90% of the problems I faced. Git seems intimidating but like anything else all it takes is a little practice.
Read the first part over: https://medium.com/swlh/practical-git-using-cli-8a7fad448e06