© Mariot Tsitoara  2020
M. TsitoaraBeginning Git and GitHubhttps://doi.org/10.1007/978-1-4842-5313-7_18

18. Common Git Problems

Mariot Tsitoara1 
(1)
Antananarivo, Madagascar
 

We’ve come a long way since our first Git command! We’ve learned a lot about basic and advanced Git features and when to use them. But since we are only humans, we’re going to face a lot of problems during our Git journey. Most of these problems are the result of inadvertences, so just being aware of their existence is a big step forward toward avoiding them. But if you still run into them, here are the best solutions!

Repository

The repository is the backbone of your Git experience; everything begins and ends there. It’s very difficult to mess it up, but in the slight chance something bad happens, here are some tips.

Starting over

This is the most radical “solution” in the chapter, and I hope you won’t ever use it. This solution is basically a way to delete everything and start over! This should only be an option when you have a remote repository and you want to delete your local one for some reason. Reasons to do this include
  • Change of work computers

  • Unreadable sectors in hard drive

  • Unrecoverable errors in “.git” directory

To start over, you just need to clone the remote repository with the git clone command:
$ git clone <repository_location>

The repository location is the HTTPS or SSH link to your remote repository; you can find it on your GitHub project page.

Cloning has the same effect as initializing a repository but with a big bonus: all history and commits will also be copied on your new local repository. And you won’t need to precise the origin link anymore.

Change origin

Under normal circumstances, you would want to keep the remote repository’s URL the same throughout your development. But there are certain circumstances where it’s necessary to change it:
  • Switching between HTTPS and SSH links

  • Transfer of the repository to another host

  • Addition of dedicated repository for release or testing

First, let’s get some more information about our current remotes. To do so, use the git remote command with the “-v” option.
$ git remote -v
This will give you a list of your current remotes, as shown in Figure 18-1.
../images/484631_1_En_18_Chapter/484631_1_En_18_Fig1_HTML.jpg
Figure 18-1

List of current remotes

Here, we only have one remote “origin” that points to a GitHub HTTPS link. To modify this link, you will need to use the set-url subcommand:
$ git remote set-url <remote_name> <remote_url>
For example, if I wanted to switch to SSH instead of HTTPS for my GitHub access, I would execute
$ git remote set-url origin [email protected]:mtsitoara/todo-list.git

Doing this will allow me to push and pull to-and-from GitHub without providing my username and password. The authentication will be done by two sets of keys: a private key that I keep on my local computer and a public key that I must upload to GitHub. If you are interested in using SSH for your authentication, please head over to GitHub help for more information depending on your Operating System (https://help.github.com/en/articles/which-remote-url-should-i-use). If you decide to keep using HTTPS but what to cache for password so you don’t have to type it all the time, you can use a credential helper. Again, there is more information about this on GitHub help, depending on your Operating System (https://help.github.com/en/articles/caching-your-github-password-in-git).

Caution

If you change your remote name, don’t forget to use the new name for every push and pull action.

Working Directory

You will spend most for your time on the Working Directory, and here again, there’s not a lot of thing you can break.

Git diff is empty

This comes up a lot but it’s not dangerous. Sometimes, you made a lot of changes and want to check the changes. But when you run git diff, the result is empty. Don’t panic! Git diff only shows modified files, so if your file is staged, you won’t see it there. To see changes done to staged files, you must run:
$ git diff --staged

Tip

Using a GUI tool would help you greatly when reviewing changes.

Undo changes to a file

This will come up a lot when you’ll use Git. Sometimes, you just want to revert a file back to its previous state without having to check out an entire commit and then copy-paste the code. We’ve already seen the command earlier:
$ git checkout <commit_name> -- <file_name>

This command will check out the file as it was on the commit and, thus, will change your Working Directory. Careful not to lose any uncommitted changes!

Commits

Most problems will arise when you’ll try to commit your current project. But don’t worry, there is always a simple solution for these kinds of problems. The most important thing to consider is: are the commands you are using destructive? Commands like reset or check out change your Working Directory, so please make sure that you know what you are doing before executing them.

Error in commit

This is a basic error in Git. After you commit your hard work, you’ll sometimes notice that a little grammatical error found its way into your commit message or that you forgot to stage a file. The solution to these problems is to amend the commit, meaning that you will cancel the immediate commit and make a new one. The command is simple:
$ git commit --amend

The commit name will change because you are basically changing its content. That’s why you should not amend a commit that you’ve already pushed to a remote branch, especially if somebody else works on that branch. This is rewriting history and you should never do it.

That said, if you’ve pushed your commit and are alone on the branch, you can amend a commit and try to push it again. But since the commit name changed, Git won’t allow you to change history without a fight. You will have to erase all the history on the remote branch and replace it with yours, meaning that you will overwrite everything on the remote branch. That’s why you should never amend a commit if you aren’t alone on a branch. To push a branch with amended commits, you have the force it.
$ git push <remote_name> <branch_name> -f

The “-f” option forces Git to overwrite everything on the remote branch and replace it with your current branch history.

Caution

Rewriting history on a branch where somebody else is working is just plain rude and selfish. Don’t do it.

Amending commits should only be used when you want to modify the commit message or add/remove a file. Don’t amend a commit to change code.

Undo commits

If you committed on a branch but then realized it’s the wrong one, you can undo it, but only when you haven’t pushed to a remote branch.

The command is simple but dangerous: it’s the reset command. But contrary to the “hard” reset where everything is cleared, a “soft” reset is necessary to undo the commit but keep the changes.
$ git reset HEAD~ --soft

The commit will then disappear, leaving you with some option to stash the changes and apply them to another branch.

Again, this is rewriting history and should not be used if you’ve already pushed to a remote branch.

Branches

You will need to work with branches a lot to have an optimized workflow. When working on a new feature or bugfix, your first instinct should be the creation of a branch. But the more you are getting comfortable with branches, the more you are likely to forget a little detail that can lead to problems. Here are the most common problems that you will encounter with Git.

Detached HEAD

HEAD is a reference to the current checked-out commit, meaning the parent commit of any future commit you will create. Usually, HEAD points to the last commit of the current branch; and all future branches and commits will have it as parent.

When you check out branches, the HEAD will go back and forth between the last commits of the branches. But when you check out a specific commit, you enter a state called “detached HEAD” which means that you are in a state where nothing you will create will be attached to anything. It’s useless then to try to commit during that state as any change will be lost.

Git will tell you when you are in that state (like in Figure 18-2) so you won’t ever be in that state unknowingly.
../images/484631_1_En_18_Chapter/484631_1_En_18_Fig2_HTML.jpg
Figure 18-2

Checking out a commit

Checking out a commit is thus only needed to test something on your software. You can, however, create a branch from that specific commit if you want to keep the commits you intend to make. The command is the same as creating a branch from another branch:
$ git checkout -b <branch_name>

Worked on wrong branch

This happens a lot. The situation is usually like this: you receive a task and you are so eager to complete it that you begin to code immediately. You are already an hour into the task when you notice that you were working the master branch all along! Don’t worry, it’s very simple to resolve this.

If you modified some files on the wrong branch, you can directly create a new branch (and check it out) to take the current changes there. It’s the same command again:
$ git checkout -b <branch_name>

This will create a new branch with your current changes and check it out. You can then stage your modified files and commit the project.

However, this won’t work if you’ve already pushed the branch to a remote repository; history is history, don’t change it. The only way to fix that is to revert the commit you push and live with that shame all your life.

Catch up with parent branch

When you create a branch from another (usually master), their histories are not linked anymore, so what happens in a branch doesn’t have any incidence on the other. This means that while you are working on your branch, other people can commit on the base branch; and those commits won’t be available to your branch.

If you are still working your branch but are interested in having those new commits on the base branch, you must first have a clean plate, meaning that you must commit your project (or stash your current changes).

You then have to check out the parent branch, pull the new commits, and then go back to your branch.
$ git checkout master
$ git pull origin master
$ git checkout <branch_name>
Safely on your local branch, you can then catch up to the parent branch. The concept is simple: Git will take out your current commits and create new branch from the tip of the parent branch; your commits will then be applied on your new branch. It would be like you create a branch from the latest commit of the master branch. The command is called rebase.
$ git rebase master

The commits on master might introduce conflicts in your branch, so be prepared to get your hands dirty. The resolving of those merge conflicts is the same as what we’ve seen previously: open each conflicted file and choose which code you want to keep; then you can stage them and commit.

You can find an example of rebase conflict in Figure 18-3, on which commits on master and test_branch both modified README.md.
../images/484631_1_En_18_Chapter/484631_1_En_18_Fig3_HTML.jpg
Figure 18-3

Merge conflict during rebase

As you can see, it’s almost exactly like any merge conflict; and the resolution is the same:
$ git add <conflicted_files>
$ git rebase --continue
Here also, if you are not feeling brave enough for conflicts, you can abort the rebase and go back to the initial state.
$ git rebase --abort

If you work on a branch for a long time, it’s a good idea to rebase from time to time, so you aren’t left too far behind the parent branch. Of course, you can face merge conflicts, but those are more and more likely to appear the bigger your changes are. And if you delay rebases for a fear of conflicts, you will only set yourself up for failures because those conflicts will appear again when you’ll attempt to merge the branches anyway. It’s better to deal with small conflicts with a rebase from time to time than have to merge a lot of conflicted files at the same time on merge.

Branches have diverged

This will happen to you if you are using a bad Git workflow. As we said earlier, you should work on your own branch to resolve an issue, because multiple people committing on the same branch is the perfect recipe for disaster.

We say that two branches are diverged when you can’t push to your remote branch anymore due to a history change. This happens when you committed on your local branch, but other people have pushed their commits on the remote branch before you. Come the time to push, Git won’t let you because the last commit of the remote branch isn’t part of your local history. You will get an error like the one shown in Figure 18-4.
../images/484631_1_En_18_Chapter/484631_1_En_18_Fig4_HTML.jpg
Figure 18-4

Rejected changes

Here is the most sensible solution: pull the commits for the remote branch and merge your changes. You will then have their changes on your history (after resolving the eventual merge conflicts) and can push afterward.
$ git pull origin <branch_name>
$ git push origin <branch_name>
This will give you an ugly history log, but at least all commits are saved. An example of this is shown in Figure 18-5.
../images/484631_1_En_18_Chapter/484631_1_En_18_Fig5_HTML.jpg
Figure 18-5

Merge local and remote branch

The other solution is more brutal: overwrite everything on the remote branch and replace its history by yours. To do so, you must push using the “force” option.
$ git push origin <branch_name> -f

This results in lost commits and fistfight; don’t ever do this.

Again, this shouldn’t happen if you use a good Git and GitHub workflow.

Summary

This chapter is there to point you to the right solution when faced with common Git problems. Surely, you’ll discover new, harder problems but it’s a good way to start. The main thing to remember is always to check where you are before doing anything, especially committing.

But these problems shouldn’t appear at all if you use the common Git and GitHub workflow. So, let’s rediscover that in the next chapter. We’ve already talked about this in the earlier chapters, but it’s time to review it after you’ve seen all the most used Git and GitHub features.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.12.161.77