Collaborating with a remote repository
Overview
Teaching: 25 min
Exercises: 15 minQuestions
How do I update my local repository with changes from the remote?
How can I collaborate using Git?
Objectives
Understand how to pull changes from remote repository
Understand how to resolve merge conflicts
Pulling changes from a remote repository
Now when we have a remote repository, we can share it and collaborate with others (and we can also work from multiple locations: for example from a laptop and a desktop in the lab). But how do we get the latest changes? One way is simply to clone the repository every time but this is inefficient, especially if our repository is very large. So, Git allows us to get the latest changes down from a repository.
We’ll first do a “dry run” of pulling changes from a remote repository and then we’ll work in pairs for some real-life practice.
First, let us leave our current local repository,
$ cd ..
$ ls
$ conversions
And let us clone our repository again, but this time specify the local directory name,
$ git clone https://github.com/<USERNAME>/conversions.git laptop_conversions
Cloning into 'laptop_conversions'...
So we now have two clones of our repository,
$ ls
$ conversions laptop_conversions
Let’s pretend these clones are on two separate machines! So we have 3 versions
of our repository - our two local versions, on our separate machines (we’re
still pretending!) and one on GitHub. So let’s go into one of our clones,
update temperature_conversions.m
to add a Kelvin–Celsius line to our graph,
commit the file and push these changes to GitHub.
$ cd conversions # Change current directory
Modify the script from the conversions
directory so that the final section is as below:
% Plot Fahrenheit vs Celsius
degC = linspace(0,100,101);
plot(degC, celsius_to_fahrenheit(degC))
hold on
degK = linspace(273, 373, 101);
plot(kelvin_to_celsius(degK), degK)
xlabel('Celsius')
ylabel('Conversion')
legend('Fahrenheit', 'Kelvin', 'location', 'northwest')
Now commit the file and push:
$ git add temperature_conversions.m
$ git commit -m "Add K-C conversion trace to graph"
$ git push origin master
Now let’s change to our other repository and fetch
the changes from our
remote repository,
$ cd ../laptop_conversions # Switch to the other directory
$ git fetch
We can now see what the differences are by doing,
$ git diff origin/master
which compares our current, master
branch, with an origin/master
branch
which is the name of the master
branch in origin
which is the alias for our
cloned repository, the one on GitHub.
We can then merge
these changes into our current repository, which merges the
branches together,
$ git merge origin/master
And then we can check that we have our changes,
$ cat temperature_conversions.m
$ git log
As a short-hand, we can do a git pull
which does a git fetch
then a git merge
.
Now try the same process, but this time starting in the laptop_conversions
folder (you
should already be in the laptop_conversions
folder).
Modify the script as below, to add a Newton-Celsius conversion trace to the graph,
xlabel('Celsius')
ylabel('Conversion')
degN = linspace(0, 33, 34);
plot(newton_to_celsius(degN), degN)
xlim([0, 100])
legend('Fahrenheit', 'Kelvin', 'Newton', 'location', 'northwest')
then commit and push the changes:
$ notepad temperature_conversions.m # Add code above
$ git add temperature_conversions.m
$ git commit -m "Add N-C conversion to graph"
$ git push origin master
$ cd ../conversions # Switch back to the conversions directory
$ git pull origin master # Get changes from remote repository
Now we can check that we have our changes,
$ cat temperature_conversions.m
$ git log
Fetch
vspull
If
git pull
is a shortcut forgit fetch
followed bygit merge
then, why would you ever want to do these steps separately?Well, depending on what the commits on the remote branch contain, you might want to:
- abandon your local commits before merging (e.g. your local commits duplicate the changes on the remote),
- rebase your local branch to avoid a merge commit,
- do something else.
Fetching first lets you inspect the changes before deciding what you want to do with them.
Conflicts and how to resolve them
Let’s continue to pretend that our two local, cloned, repositories are hosted on two different machines. You should still be in the original conversions folder. Modify the H1 line to indicate the script produces a conversion graph, as shown below.
%TEMPERATURE_CONVERSIONS
% Display graph of temperature conversions between C, F, K, and N.
% Check temperature conversions between Kelvin, Fahrenheit, Celsius and
% Newton
Then push these changes to our remote repository:
$ git add temperature_conversions.m
$ git commit -m "Detail graph in H1 line"
$ git push origin master
Now let us suppose, at a later, date, we use our other repository and we want to clarify the wording of the help text. Currently it says that it checks temperature conversions, but actually, it only prints some conversions — there is no checking that the values are correct.
$ cd ../laptop_conversions # Switch directory to other copy of our repository
Now edit temperature_conversions.m
as below
%TEMPERATURE_CONVERSIONS
% Print key temperature conversions between Kelvin, Fahrenheit, Celsius and
% Newton
Commit and push your changes.
$ git add temperature_conversions.m
$ git commit -m "Clarify script behaviour in H1 line"
$ git push origin master
To https://github.com/<USERNAME>/conversions.git
! [rejected] master -> master (fetch first)
error: failed to push some refs to 'https://github.com/<USERNAME>/conversions.git'
hint: Updates were rejected because the remote contains work that you do
hint: not have locally. This is usually caused by another repository pushing
hint: to the same ref. You may want to first integrate the remote changes
hint: (e.g., 'git pull ...') before pushing again.
hint: See the 'Note about fast-forwards' in 'git push --help' for details.
Our push fails, as we’ve not yet pulled down our changes from our remote repository. Before pushing we should always pull, so let’s do that…
$ git pull origin master
and we get:
Auto-merging temperature_conversions.m
CONFLICT (content): Merge conflict in temperature_conversions.m
Automatic merge failed; fix conflicts and then commit the result.
As we saw earlier, with the fetch and merge, a git pull
pulls down changes from the
repository and tries to merge them. It does this on a file-by-file basis,
merging files line by line. We get a conflict if a file has changes that
affect the same lines and those changes can’t be seamlessly merged. We had this
situation before when we worked with branches and tried to merge two of them. If
we look at the status,
$ git status
we can see that our file is listed as Unmerged and if we look at temperature_conversions.m, we see something like:
<<<<<<< HEAD
% Print key temperature conversions between Kelvin, Fahrenheit, Celsius and
=======
% Display graph of temperature conversions between C, F, K, and N.
% Check temperature conversions between Kelvin, Fahrenheit, Celsius and
>>>>>>> 11c745bbc1e31eccff832acd0b8b11ab9127fce2
The mark-up shows us the parts of the file causing the conflict and the versions they come from. We now need to manually edit the file to resolve the conflict. Just like we did when we had to deal with the conflict when we were merging the branches.
Edit the file as shown below.
%TEMPERATURE_CONVERSIONS
% Display graph of temperature conversions between C, F, K, and N.
% Print key temperature conversions between Kelvin, Fahrenheit, Celsius and
% Newton
Then commit the changes. Now, if we push …
$ git add temperature_conversions.m # Stage the file after resolving the conflict
$ git commit # Commit to mark the conflict as resolved
$ git push origin master
… all goes well. If we now go to GitHub and click on the Overview tab we can see where our repository diverged and came together again.
This is where version control proves itself better than DropBox or GoogleDrive, this ability to merge text files line-by-line and highlight the conflicts between them, so no work is ever lost.
Collaborating on a remote repository
In this exercise you should work with a partner or a group of three. One of you should give access to your remote repository on GitHub to the others (by selecting
Settings -> Collaborators
).Now those of you who are added as collaborators should clone the repository of the first person on your machines. (make sure that you don’t clone into a directory that is already a repository!)
Each of you should now make some changes to the files in the repository. Commit the changes and then push them back to the remote repository.
Remember to pull changes before you push.
Creating branches and sharing them in the remote repository
Working with the same remote repository, each of you should create a new branch locally and push it back to the remote repo.
Each person should use a different name for their local branch. The following commands assume your new branch is called
new_branch
– you should use the name of your local branch instead ofnew_branch
.$ git push origin new_branch # Substitute your local branch name for 'new_branch'.
The other person should try to get local copies of the branches created by others (so eventually everybody should have the same number of branches as the remote repository).
To fetch new branches from the remote repository (into your local
.git
database):$ git fetch origin
Counting objects: 3, done. remote: Compressing objects: 100% (3/3), done. remote: Total 3 (delta 0), reused 2 (delta 0) Unpacking objects: 100% (3/3), done. From https://github.com/apawlik/conversions 9e1705a..640210a master -> origin/master * [new branch] new_branch -> origin/new_branch
Your local repository should now contain all the branches from the remote repository, but the
fetch
command doesn’t actually update your local branches.The next step is to check out a new branch locally to track the upstream branch i.e. the remote branch.
$ git checkout new_branch
Branch new_branch set up to track remote branch new_branch from origin. Switched to a new branch 'new_branch'
Undoing changes using revert
Once you have the branches which others created, try to undo one of the commits.
Each one of you should try to revert a commit in a different branch to your partner(s).
Push the branch back to the remote repository. The others should pull that branch to get the changes you made.
What is the end result? What happens when you pull the branch that your colleagues changed using
git revert
?Solution
The revert shows up in everyone’s copy. You should always use
revert
to undo changes which have been shared with others.
Key Points
git pull
to integrate remote changes into local copy of repository