Chapter 18 Git basics

18.1 Introducing yourself

Git will first need to know who you are. You can specify this using Git Bash. Note that it’s important to use the email address that you also used for your Git repo manager account, because when Git talks to that that server, that email address is how you’ll be identified. To set your username and email address, use:

git config --global user.name "Gjalt-Jorn Peters"
git config --global user.email "gjalt-jorn@behaviorchange.eu"

Note that you should probably use your own name and email address, though.

The first time you’ll ask Git to do something that requires it to authenthicate with the Git server hosting the remote repository, Git will ask for your password. Usually, Git will store this in its credential manager so you’ll only have to provide it once.

18.2 Changing a commit

Sometimes you want to change a commit (called “amending” in Git), for example because you hadn’t yet configured your username or you made a typo in the commit message.

To change the user making the commit, use:

git commit --amend --author="Author Name <email@address.com>"

To change the message, use:

git commit --amend -m "New Commit Message"

18.3 Unsetting your password

Sometimes you may want/need to force Git to forget your password. Operating systems often come with thir own credential managers that applications can use to store passwords, but Git also has its own credential manager. Which one Git uses depends on how you configure Git (it lets you choose when you install it, but you can also change this later on).

A number of methods to reset your password are listed on this Stack Overflow page.

I think this one either always works, or only if you use the inbuilt Git credential manager:

git config --global --unset user.password

These ones are suggested when you use the Windows and macOS credential managers, respectively:

git config --global credential.helper wincred
git config --global credential.helper osxkeychain

If none of these work, see the original Stack Overflow post (WayBack Machine version archived here).

18.4 Getting started: cloning

To get started with a repository, you clone it to your local computer. Cloning a repository not only downloads all current versions of the files, but it downloads the entire repository - and therefore, also the complete history of the project. With large projects, this may become quite a large project. However, the advantage is that you can then locally inspect the entire history.

After you cloned the repository, you can make changes to the files and synchronize those with the repo. Note that sometimes, you may want to create a new repository. Although you can do this directory with Git, unless you know what you’re doing, you’ll probably want to initiate new repositories using a central repository suite such as GitLab. Therefore, see Chapter @ref{managing-a-gitlab-project} for instructions on how to initiate a new Git repo. Once you created a new repository at a GitLab server, you will still have to clone it to your local PC before you can start working with it.

Once you cloned a repository to your local machine, you can start working on the files it contains. If you want to try it out, you can open a Git Bash session in a directory where you’d like to clone a repository, and clone the repository containing this book by typing:

git clone https://gitlab.com/psy-ops/psy-ops-guide.git

For more information about cloning, see https://git-scm.com/book/en/v2/Git-Basics-Getting-a-Git-Repository.

18.5 Working on files in a repo: pulling, committing, and pushing

Working on files in a Git repository is no different from working on files that are not in a Git repository. Just use whichever software you prefer to make your edits. However, once you realised one or more changes (that are more or less coherent), you will want to package them up and synchronize them.

In Git, this is called committing the files to the repository. If you create a so-called commit, you basically tell Git to take all (or some) changes that were made to all (or some) of the files in the repository that Git tracks (and you can specify which files Git shouldn’t track, or in other words, which files Git should ignore: see section 18.6), and bundle them together in a package (i.e. a commit). Each commit has its own commit message, where you can (and have to; commit messages are not optional) explain what you did (and maybe why you did that).

To create a commit you have to first stage one or more files. If you work on a project that is very important and/or collaborate heavily using Git and/or have the discipline to keep finegrained documentation of what changes you make and why, you will probably not commit too many changes at once. However, in most cases, I just stage and then commit all changes I made in one go.

To stage all modified files (that includes created and deleted files and directories), use the following command:

git add .

To then specify a commit message, use:

git commit -m "This is a message"

This wraps all those changes up into one commit with that message associated to it.

Commits are created locally. In other words, you don’t need an internet connection - which also means that creating the commit, or a whole bunch of commits if you’re on a roll, does nothing to synchronize your local repository with the central one (and therefore, with the repo’s on everybody else’s machine).

To actually push the commits to the central repository, you have to literally tell Git to do that:

git push

Note that to push to a repository, you need to have be authorized to do so (see the Rights section above).

If there’s pushing, there’s also pulling. Where pushing sends all your commits to the remote repository, pulling downloads all changes from the remote repository that you didn’t yet have locally. In other words, if somebody else changed one or more files since the last time you told Git to pull, pulling will download those change to your computer, overwriting the old files.

You can pull with:

git pull

Because you will want to avoid working on an outdated version of a file, it is wise to always pull all recent changes into your local repository before you start working on anything. So, normally, you pull, work on files and stash your changes into one or more commits, and push either after each commit or set of commits, or when you’re done working in the repository for the day.

If you try to push commits to the remote repository, but the remote repository has been updated in the meantime, Git will refuse. It will tell you that the remote repository contains work you don’t have locally, and that you have to pull first. So, in that case you pull first. Sometimes, Git also refuses pulling: that happens if you made changes to one or more files that you did not yet stash in a commit yet, and that were also changed in the remote repository. In that case, you first have to make sure you create one or more commits with all changes, before you can pull the changes to your local machine. If the same parts of one or more files were changed, you have a merge conflict: you’ll have to tell Git which bits to use. This is discussed in section 18.7.

Commit messages have a useful extra functionality. If you use a Git repo management suite, such as GitLab (or GitHub), these often parse the commit messages and allow you to specify actions that they can then take. For example, in more complicated projects, in projects where an overview and structure and very important, or in projects that just involve people who really like an overview and structure, you may want to use issues, a feature of Git repo management suites. Issues allow you to keep track of tasks relating to the project, and GitLab has a so-called quick action that allows you to specify that a commit closes an issue. If you use this quick action in your commit message, GitLab will close the issue with a message that links to that commit. This is a very efficient way to keep track of progress in the project.

18.6 Preventing files from syncing

You will usually not want to synchronize all files in a directory: projects may contain files including personal data (e.g. raw data) or secrets (e.g. passwords). Git allows you to specify the files to ignore in a file called “.gitignore”. Each line in the gitignore file specified a pattern, and all directories and files matching the pattern are ignored. Details are described in the relevant page of the Git manual.

_PRIVATE_

18.7 Merge conflicts

Normally, if you collaborate in a project, there will be some division of labour, making it unlikely that two people work on the same file at the same time. However, still you may sometimes run into situations where you did edit one or more lines in a file that somebody else edited at the same time.

In that case, probably just after Git forced you to pull recent changes from the remote repository, Git will present you with a merge conflict. In the files that were simultaneously edited locally (by you) and remotely (by somebody else who had already pushed their changes to the server), Git will insert both fragments (i.e. both versions of the conflicting lines), delimited bt three lines produced by Git.

Your job is now to manually merge both versions and by doing so, resolve each conflict. You do this simply by editing the file until it has the state you want it to have. You have three alternatives. First, you can select your version of the file content on those conflicting lines, in which case you remove the version produced by somebody else, as well as the three delimiting lines Git added. Second, you can retain the changes that the other person made, and remove your own version (as well as the three delimiting lines Git added). Or, third, you can really merge both versions into one ‘best of both worlds’ version, and then remove the three delimiting lines.

After you resolved all merge conflicts you stash those changes into a commit (or into several commits), and push them to the server.

18.8 Resolving merge conflicts

To see an overview of all files that currently have merge conflicts, use:

git diff --name-only --diff-filter=U

To unstage all files, in case you had staged it for committing before realising it had a merge conflict, use:

git reset

You can also specify the path to a file, if you just want to unstage one file:

git reset -- <path>

Replace <path> with the path to the file.

18.9 Renaming a repository

To rename a repository URL, change it in e.g. GitLab and then adjust it in your local Git repo using, for example:

git remote set-url origin https://gitlab.com/USERNAME/REPOSITORY.git

You can check the remote URL using:

git remote -v

18.10 Advanced: branching