Language
Category
Search

Using Git to share and collaborate on a project

How to clone a project, make changes and merge them, customize history queries, name commits as versions and compare them, search using Git and more useful commands

At Terminal By Rudi Drusian Lange
Published on
Last updated

Before you start

This text covers the use of Git for project collaboration and assumes knowledge of the information covered in the first part of this article: Learning the basics of git and the use of branches, read first to facilitate understanding of the text below.

Getting started

This article will use two fictional characters: Jessica, who has started a new project with a Git repository located at /home/jessica/project, and Jason, who has a user on the same system and wants to contribute to the project using the /home/jason/project-jessica directory.

Assuming that Jessica's Git repository has already been created, Jason starts by cloning Jessica's project into his contribution directory:

Jason

cd /home/jason/
git clone /home/jessica/project projeto-jessica

Then Jason makes his changes:

Jason

# (Edit files)
git commit -a

At the end he asks Jessica to apply his updates to the original repository. So Jessica does it:

Jessica

cd /home/jessica/project
git pull /home/jason/project-jessica

This causes file updates made in the master branch of Jason's repository to be applied to the branch Jessica was in when she ran the command. The git pull command fetches the changes made from the remote repository and then merges them with the current branch.

If a conflict occurs, Jessica will have to resolve them locally in her directory, Git will still fetch the changes but will refuse to merge them until the corrections are made.

Jessica can check the changes made by Jason before merge them using the git fetch command:

Jessica

git fetch /home/jason/project-jessica
git log -p HEAD..FETCH_HEAD

To see all the changes Jason has made since the project was cloned, she can use the command:

Jessica

gitk HEAD..FETCH_HEAD

Note that this two-dot range notation .. can be used with both the git log command and gitk. If Jessica wants to see both the changes she has made and the changes Jason has made since the project was cloned, she can use the ... three-dot range notation.

Jessica

gitk HEAD...FETCH_HEAD

If Jessica decides that there are no relevant changes made by Jason, she can continue working normally, while if Jason's history shows something she really needs, she can run git pull and continue working relying on the recent changes made by Jason.

Depending on the project, there may be a need to interact with the remote repository constantly. To facilitate this process, it is possible to create an alias:

Jessica

git remote add jason /home/jason/project-jessica

# And then
git fetch jason

The creation of the alias makes it possible to use the jason/master form to access information already fetched with the git fetch command, as in the example:

Jessica

git log -p master..jason/master

The command above shows a list of all the changes Jason has made since the first clone was made. After analyzing these changes, Jessica could apply them with:

Jessica

git merge jason/master

# or fetch from hers remote branches
git pull . remotes/jason/master

Later, Jason may want to fetch Jessica's latest updates and he does so with the remote:

Jason

git pull

As Jason's repository was cloned from Jessica's, you don't need to enter the path to the repository, Git already stores this information and uses it in the git pull command.

Jason

# Shows the path of the original project
git config --get remote.origin.url /home/jessica/project # Shows the configurations created by the git clone git config -l # Git keeps a copy of Jessica's master branch called origin/master git branch -r
# Jason can continue working from another machine using ssh git clone jessica.org:/home/jessica/project projeto-jessica

Exploring History

The Git history is represented as a series of commits that can be listed with the command:

git log

commit 82407449e223ddfd0b8e9ef6df95c8cd156e82b1
Author: Jason <jason@email.org>
Date:   Tue May 14 21:37:07 2024 -0300 merge: Added comment to the code

The code in the commit line can be used with the git show command for more details on this commit:

git show 82407449e223ddfd0b8e9ef6df95c8cd156e82b1

Using the beginning of the code also works, as long as it is unique, in this example using only the numbers below was enough.

git show 82407

Every commit has a parent that represents the previous state of the project.

# show the last commit of the current branch
git show HEAD

# last commit of the experimental branch
git show experimental

# to see the parent of HEAD
git show HEAD^

# to see the grandparent of HEAD
git show HEAD^^

# to see the great-great grandparent of HEAD
git show HEAD~4

# merge commits may have more than one parent

# show the first parent of HEAD (same as HEAD^)
git show HEAD^1

# show the second parent of HEAD
git show HEAD^2

Naming commits

You can name a commit with:

git tag v2.5 82407

It is now possible to refer to the commit that starts with 82407 using the name v2.5. In order for this name to be valid for other people you need to create a tag object and perhaps sign it, look for details on the git tag command for more information.

Names can be used in Git commands whenever you need to refer to a commit, examples:

# compare the current HEAD to v2.5
git diff v2.5 HEAD

# create a new branch named "stable" based at v2.5
git branch stable v2.5

# reset your current branch and working directory to its state at HEAD^
git reset --hard HEAD^

Beware of the reset command: in addition to losing any changes that have not yet been saved, it will also remove the latest commits from this branch, if this branch is the only one containing those commits, they will be lost. Also, don't use git reset on a publicly-visible branch that other developers pull from. If you need to revert changes applied with push, use git revert instead.

Using range with git log

# commits between v2.5 and v2.6
git log v2.5..v2.6

# commits since v2.5
git log v2.5..

# commits from the last 2 weeks
git log --since="2 weeks ago"

# commits since v2.5 which modify Makefile
git log v2.5.. Makefile

If the stable and master branches diverged from a common point some time ago:

# list commits made in the master but not in the stable branch
git log stable..master

# Opposite of the command above
git log master..stable

The git log command has a weakness because it displays commits in list format. When the history has lines of development that diverged and then merged again, the order shown in the command is irrelevant.

In these cases, the gitk command is better for viewing histories.

# Commits from the last two weeks with changes to files in the drivers folder
gitk --since="2 weeks ago" drivers/

Using versions and filenames:

# Compares files in different versions
git diff v2.5:Makefile HEAD:Makefile.in

# View the file in a specific version
git show v2.5:Makefile

Searching

The git grep command is used to search for strings in project files:

# Recursively searches for "import" in files in the current directory
git grep "import"

# Search for "import" in commit v2.5
git grep "import" v2.5

Final Thoughts

Adding up this tutorial and its first part should be enough to have a basic distributed revision control for your projects. Two simple ideas help you understand the depth and power of Git:

  • The object database is the system used to store the history of your projects, files, directories and commits.
  • The index file is a cache of the directory tree state that is used to create commits, check working directories and contain the various trees involved in a merge.

Sources

This is not my original language and I don't speak it very well. I used my little knowledge and translators tools to compose the text of this article. Sorry for possible spelling or grammatical errors, suggestions for corrections are appreciated and can be sent to the contact email in the footer of the site. My intention is to share some knowledge and I hope this translation is good enough.