In this blog post, we will take a quick look at Git and the problem of unrelated histories during Git merge. We will also look at a way to solve the unrelated history problem.
1. Introduction to Git
Git is a distributed version control system for tracking changes in source code during software development. It is designed for coordinating work among programmers, but it can be used to track changes in any set of files. Its goals include speed, data integrity and support for distributed, non-linear workflows. Git is free and open-source software distributed under the terms of the GNU General Public License version 2.
The major difference between Git and any other VCS is the way Git thinks about its data. Conceptually, most other systems store information as a list of file-based changes. Git thinks of its data more like a set of snapshots of a mini filesystem. Every time you commit, or save the state of your project in Git, it basically takes a picture of what all your files look like at that moment and stores a reference to that snapshot. To be efficient, if files have not changed, Git doesn’t store the file again—just a link to the previous identical file it has already stored. Git has detailed documentation specified in the URL.
1.1 Git Commands
These are some of the common git commands which are usefulStatus Command
This is used to add the check the status of all the files under git consideration
- untracked – This is the initial state. The file is not tracked by git so far and will be tracked after adding to local repository.
- staged- This is the state for a tracked file but the latest changes have not been committed.
- Committed – The file has been committed to the local repository but it is not available in the remote repository.
This is used to add the file to the local repository for committing. The file is supposed to be in staged state once the command has been executedCommit Command
git commit -m 'Commit 1'
This is used to commit the file to the local repository. Each commit needs a message to indicate the reason for the commit which is provided by the
-m flag.Push Command
git push origin master
This is used to push our commits to the remote repository. A single commit contains multiple files and their changes. Once the commit is pushed, a success message gets displayed on the screen. Here, origin refers to the remote branch pointer while master is the remote branch.Pull Command
Ideally, a git repository is used by multiple folks and can have commits at various intervals. In order to push our commits, We need to pull in the remote changes. This is done by the above command. The default execution of this does a merge operation which tries to merge the remote with our local and this is indicated by a merge commit.
Alternatively, to maintain a linear history We should use the
-r flag which rebases instead of merge. Here there is no separate merge commit and local commits are added on top of remote commits indicating a linear history.
2. Multiple Repositories
In this section, we will look at a specific problem with Git and in the next section, we will look at a way to solve it. Let’s start by creating a new git repository using the below commands
mkdir test cd test git init
The next step is to create a text file 1.txt and commit the text file to the local repository.
echo "Hi" >> 1.txt git add 1.txt git commit -m 'First commit'
- We create a simple text file using the
- We add the file 1.txt to the local repository.
- We commit our changes with a commit message to reveal the intent of the commit.
Our changes are saved to the local repository but we need to add our commits to the remote repository so that our changes can be shared with other people. We come to know that a remote repository already exists. So the next step is synchronizing with the remote repository. To achieve this, We execute the following command
git remote add origin email@example.com:user/repo.git
Local repository pointer has been updated to refer to the remote repository with the above command. Next step is to pull the related remote changes from the repository.
git pull origin master
- We specify the remote branch as
masterfrom which the changes have to be pulled.
originpointer is the remote branch tip.
Running the above command results in the following error
from github.com:rparthas/JCG * branch master -> FETCH_HEAD * [new branch] master -> origin/master fatal: refusing to merge unrelated histories
This error occurs as Git is unable to reconcile the local repository with the remote repository. The history of commits for these two are very different and Git is unable to reconcile them.
3. Fixing unrelated Histories
To fix the above issue, We can follow multiple actions. One action is to first clone the remote repository and add our commits to the repository. This approach is easy if the number of commits is less. But a better approach is to run the pull command with the following options.
git pull origin master --allow-unrelated-histories
The above option overrides git behavior and merges the remote repository with the local repository. In case of any merge conflicts between the files, it has to be manually resolved and add the file. Once the remote commits have been merged with the local repository, we can push our changes to the remote repository using the
git push command.
In this post, we briefly looked at creating a local repository and merging with remote repository. We looked at the unrelated history issue during the merge and looked at an effective solution for resolving the problem.