Lab 03
In this lab session you will practice the command line basics of git and a strategy to keep the repository clear of clutter. You do not need to download any new code for this lab session.
Git commands
The git
command line tool allows you to initialize or replicate repositories, query and modify the git graph state,
and resolve conflicting concurrent commits.
- In the last lecture you've learned the theory and basic commands for the most basic situations.
- Now it is your turn to gain practical proficiency with the
git
command line tool.
Online repository setup
Repositories can be initialized locally or server sided. In this first exercise you will initialize a repository locally and then transfer your full repository state to a server sided copy.
Your turn
- Setup a local sample repo
- Create a new project folder, e.g.
lab04
. - Go inside your folder and create a new text file, e.g.
rabbit.txt
- Copy your favourite communal ascii-art animal into the text file. You can also use this sample:
- Initialize your local repository, with the
git init
command. - Use the sequence of
add
andcommit
seen in class to create a first commit, containing your ascii art file.
- Create a new project folder, e.g.
- Prepare a server side repo
- Log into the UQÀM GitLab webserver
- Create a new project, private visibility
- Use the commands seen in the last lecture link your previously created local repo to the server side project
- Synchronize the server (remote) repository
- Push your first local commit to the server (do not forget the
origin
option for the first commit) - Refresh the project page and verify your ascii art is stored on server side
- Push your first local commit to the server (do not forget the
Diagnostics
Git internally uses a graph model, where commits are graph nodes. It is vital to know the state of the graph, and which changes on local files are staged to be added to the graph. In class you've learned about two git commands, to obtain diagnostics.
Your turn
- Use the
git log
command to inspect the commits in your repository.- In the last course unit we've seen an extension of the
git log
command, which allows you to display a textual representation of how commits are connected. Use the command extension and compare the output. What has changed ? git log
only shows information about commits, but not about recent file changes, that could be added to subsequent commits. Which command is used to inspect how local files relate to the latest commit ?
- In the last course unit we've seen an extension of the
- Use
git status
and carefully read the output - Modify the local state of your repository:
- Create a new file, e.g.
anything.txt
- Also make a little change to your ascii animal, e.g. add a line with "
<3 <3 <3
"
- Create a new file, e.g.
- Re-run
git status
, then carefully read the output- What is the semantic of "Changes to be committed"? Explain the output.
- What is the semantic of "Changes not staged to commit"? Explain the output.
Navigating the graph
You should now have at least two commits in your graph. In class you've seen a command to navigate between commits, that is change to visible content of your directory by the state of a previous commit.
Your turn
- Find the command line to navigate the path and use it to revert to the ascii animal before you added the "
<3 <3 <3
". Do that without editing the ascii animal manually. - Inspect
- Inspect the file to verify you correctly reverted the changes.
- Use the diagnostics commands seen above to inspect the git commit graph.
What happened to the most recent commit ? Has it been permanently deleted ?
No, your latest commit is still here. However, by using the checkout
command you have entered "detached head" state, i.e. your graph only displays commits up to the commit you have checked out.
- Finally, restore the "
<3 <3 <3
' you just retracted.- Do not manually edit the ascii art animal to restore the "
<3 <3 <3
". - Use the corresponding git command to reattach your head, i.e. go back to the latest commit in the graph.
- Do not manually edit the ascii art animal to restore the "
Local repository clone
So far you have creates a local repository and linked it to a server side repository. The next task is to create another repository copy on a second local machine. Pair up with the person next to you, and create a second local repository clone on their machine.
Your turn
- Create a second local copy, using the steps below:
- Log in to the UQÀM GitLab webserver, find the project settings, and add your neighbour as developer.
- Have your neighbour open a terminal and clone your repository, using the unique repository address.
- Once the repository is replicated on your neighbours machine, open the ascii file and verify the content is correct.
- Make a change on your neighbour's repository copy.
- Modify the ascii-art, again, e.g. add another "
<3
" below the ascii animal. - Create a new commit with the changes and push it to the gitlab server
- Modify the ascii-art, again, e.g. add another "
- Login on the GitLab webui and verify the latest changes have been taken into account.
- On your own computer, "sync up" with the latest changes by pulling the most recent commit from the GitLab server.
- Inspect the git graph and verify both machines display the same commit history.
Creating conflicts
Git conflicts happen when two developers create diverging commits.
- In the following example you are going to pair up with your neighbour, to both make conflicting changes to the ascii art, and create diverging commits.
- When afterwards you both attempt to send your commits to the server, the second commit will be rejected. You'll see an error message similar to:
Your turn
- On each of your local clones, make a different changement to your ascii animal
- On the first machine: replace the animal's eyes by
@
symbols. - On the second machine: replace the animal's eyes by
*
symbols.
- On the first machine: replace the animal's eyes by
- Each create a new commit with your changes and attempt to push to the GitLab server
- GitLab will accept the first commit, but reject the second with an error message indicating that your local repository misses remote commits and you need to manually resolve the conflict first.
$ git push
To gitlab.info.uqam.ca:max/mytestrepo.git
! [rejected] main -> main (fetch first)
error: failed to push some refs to 'gitlab.info.uqam.ca:max/mytestrepo.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.
- The error message actually alreay indicates you how to prepare for resolving the conflicting state:
git pull
, to retrieve all server side commits you are currently lacking locally.- On git pull your local state needs to be fused with the conflicting commit on server side.
- The first time you run into this conflict, git will ask you which strategy to apply to resolve the conflict.
$ git pull
warning: no common commits
remote: Enumerating objects: 3, done.
remote: Counting objects: 100% (3/3), done.
remote: Total 3 (delta 0), reused 0 (delta 0), pack-reused 0 (from 0)
Unpacking objects: 100% (3/3), 202 bytes | 67.00 KiB/s, done.
From gitlab.info.uqam.ca:max/mytestrepo
* [new branch] main -> origin/main
hint: You have divergent branches and need to specify how to reconcile them.
hint: You can do so by running one of the following commands sometime before
hint: your next pull:
hint:
hint: git config pull.rebase false # merge
hint: git config pull.rebase true # rebase
hint: git config pull.ff only # fast-forward only
hint:
hint: You can replace "git config" with "git config --global" to set a default
hint: preference for all repositories. You can also pass --rebase, --no-rebase,
hint: or --ff-only on the command line to override the configured default per
hint: invocation.
fatal: Need to specify how to reconcile divergent branches.
Selecting a merge strategy
There are several way to resolve confliting states, which we'll delve into in more detail in a future lecture. The first time you run into a conflict git will promt you for which strategy should be applied. Configure git to use "merge", using the command: git config pull.rebase false
- Note that in either case you need to manually resolve conflicting modifications made to the same file.
- After the
pull
command, git will tell you that automatic fusion of your two commits is not possible, because you edited the same file (@
vs*
as ascii animal eyes):
- After the
Resolving conflicts
Conflicting commits occur in every project. In this exercise you learn how to resolve the issue, manually.
Your turn
- Open the animal ascii art file in your favourite text editor. You'll see some cryptic lines that have been added to your ascii art:
,\
\\\,_
<<<<<<< HEAD
\` @\
=======
\` *\
>>>>>>> 9966a96a57cee347939c2026c34d9823be7a56ad
__,.-" =__)
." )
,_/ , \/\_
\_| )_-\ \_-`
`-----` `--`
- The marked lines starting with
<<<
,===
and>>>
indicate where the different commits diverge:- The lines between
<<<<<<< HEAD
and=======
indicate changes that were done by you. - The lines between
=======
and>>>>>>> 9966a96a...
indicate changes that were retrieved from the conflicting commit.
- The lines between
- To resolve the conflit, you must decide which version should survive:
- Remove all marked lines, and keep only one of the conflicting versions, e.g.
\
*`
- Remove all marked lines, and keep only one of the conflicting versions, e.g.
- Finally, share the conflict solution with your partner:
- Add the file to a new commit, add "fixed merge conflict" as comment and push it to the server
- Pull the commit from the other computer. You should not see a conflict this time, since the merge commit you just created already resolved the conflict.
Inspect the git graph, what has happened to the conflicting commits ?
git log
will show a bifurcation where the commit for "* as eyes" took another path than "@ as eyes", afterwards there is an extra commit reuniting the paths. This is a graph representation of what happened in real life: You and your partner started from the same code state (commit), both made diverging changes, and afterwards reunited to a common ground.
File exclusions
In the previous exercise you were able to manually resolve conflicts in a file, by editing the conflicting versions in a text editor.
- Manual conflict resolution works well for source files (or any other file type that can be edited in a text editor), but absolutely not for binary files.
- Just imagine you would have had to decide on which version is correct between to marked bytecode files (CAFEBABE...).
Keep binary files out of your repository
It is important to keep binary files out of your repository, because there is no reasonable way to deal with conflicts. This holds also for generated files, because they tend to be lengthy and hard to read. Examples are .class
files, PDF
files, JPG/PNG
images, but also generated JavaDoc (html
) and jar
files. The repository should only contain what is needed to build (compile) the project, never the compiled version.
Gitignore
Binary or generated files are easily added by accident. It is a good idea to configure git, to reject certain file types
from commits in the first place. In the last cours unit you've seen how a .gitignore
file can be used to achieve this
configuration.
Your turn
- Create a new Hello-World project, in a dedicated folder.
- You can add this project as subfolder, to your existing ascii animal project.
- Use the java compiler to compile your program.
- Use the diagnostic command to query which new files have been detected by
git
- You should see a newly generated
class
files, which git lists asuntracked files
- Use the diagnostic command to query which new files have been detected by
- Create a
.gitignore
file which excludes binary files, e.g.class
files- Use the toptal generator to generate the
.gitignore
file content - Inspect the output, and copy it into your .gitignore` file
- Use the toptal generator to generate the
- Run
git status
again, how has the output changed ? What does the changed output mean ? - Run the dangerous
git add .
which adds everything in your repo- Inspect the git status again, when you deem the output clean, commit and push to the server.
- Inspect the server side status and verify there are no
class
files on server side.
Bonus Cheatsheet
The commands you've been using so far are fairly basic and you will regularly need them.
Create a cheatsheet and flashcards
You can significantly speed your TP development by gaining proficiency with the appropriate git commands for the above standard situations. Create a cheatsheet and some flashcards, and regularly train them to memorize the most standard commands. Later you will be using graphical tools to interact with git, but it is always beneficial to know the commands, e.g. to resolve an issue on a server where you have only command line access. It will pay off, guaranteed.