(Previously: Part 0 – Introduction)
Initializing a local repository
The git init command sets up a local repository in the current folder:
$ cd ~/Projects/cow_tipper $ git init
Reinitialized existing Git repository in /home/buster/Projects/cow_tipper/.git/
Change history is stored in a .git sub-directory.
Tracking changes, Staging and Committing
Tracked source files
A tracked source file is one that is understood by Git to require a change history to be saved in the repository. Our source directory may contain “tracked” and “untracked” files. We won’t be able to recover change history for an untracked file.
A commit saves a set of source file changes as a “snapshot” that can be recovered later. Commits are sequential, and have a pointer to their parent snapshot. A text message is saved along with the commit.
Staging is the process of adding a file to the set of changes that will be included in the next commit operation.
Now I need to stage my source files for the first commit:
$ git add README.md $ git add cow_tipper.py
The add command does two things:
- It marks a file as “tracked”;
- It copies the file into a staging area
Alternatively, I could just add all the files in the directory in one go:
$ git add *
At this point, all files in the folder are “tracked” and ready to be committed. We can double-check where we are at any time by asking Git using the git status command:
$ git status
On branch master Changes to be committed: (use "git restore --staged <file>" to unstage) new file: README.md new file: cow_tipper.py
Nice. Let’s save this (“commit” it) to a recoverable snapshot. We’ll use the -m switch to supply a text message directly on the command-line:
$ git commit -m "First Commit"
* * * Please tell me who you are. Run git config --global user.email "firstname.lastname@example.org" git config --global user.name "Your Name" to set your account's default identity. Omit --global to set the identity only in this repository. fatal: unable to auto-detect email address
Oops! Of course Git needs to know who we are, and even tells us what commands we need to run to do this:
$ git config --global user.email "email@example.com" $ git config --global user.name "Buster Kitten"
Now let’s re-try that commit:
$ git commit -m "First commit"
[master c9b7b58] First commit 2 files changed, 8 insertions(+) create mode 100644 README.md create mode 100644 cow_tipper.py
Success! Note that we don’t have to use the -m “message” command-line switch. If we just git commit then the default text editor will be launched so that we can edit the message. We can customize what editor is used in the configuration: See Appendix B: Customizing the Message Editor.
If we’re really in a hurry we can Stage+Commit in one command:
$ git commit -a
Speaking of configuration parameters, at any time we can ask Git to show us the configuration it’s working with, using git config:
$ git config --list --show-origin
file:/home/buster/.gitconfig firstname.lastname@example.org file:/home/buster/.gitconfig user.name=Buster Kitten file:.git/config core.repositoryformatversion=0 file:.git/config core.filemode=true file:.git/config core.bare=false file:.git/config core.logallrefupdates=true
Read more about Git configuration here: https://git-scm.com/book/en/v2/Customizing-Git-Git-Configuration.
The Git Log
Note that each commit gets an identifying hash value assigned to it. We can see the first 7 characters “c9b7b58” in that commit message output above.
The command git log will list recent commits along with their hash, author, date, and comment. The format of the output is very controllable, for example:
$ git log --pretty=format:"%h - %an, %ar : %s"
e875278 - Buster Kitten, 36 minutes ago : trialling the secondary pump control block 82c55cb - Buster Kitten, 14 hours ago : Working on the next problem. fc5fea3 - Buster Kitten, 22 hours ago : I just added a line for test purposes. aaee8e5 - Buster Kitten, 24 hours ago : Removing files we don't need. c9b7b58 - Buster Kitten, 3 days ago : First commit
I’m not going to go into depth about the Git log, so for further reading I recommend: Git Basics – Viewing the Commit History (The Git Book)
(I’ve also written about git log before: Obtaining a useful log of recent check-ins.)
Git makes this very easy to go back to the current commit’s parent, or further:
$ git revert -1 $ git revert -2
If you know the unique portion of the hash code (see the log output above), you can go back to an explicit commit point:
$ git revert 82c55cb
One important feature of a source control system is to retrieve a known snapshot from the change history. Although we can use the unique hash identifier to retrieve a specific snapshot from the repository, it is easier if we use a Tag to mark important points in the history.
Tags are named pointers to specific commit points in the repository change history. We can retrieve a copy of your tracked source files as they were at the time the tag was created. Typically tags are used to mark release points in a development process, such as “Beta 1”, “Beta 2”, “version 0.0.7”, etc.
Creating a tag
We use the git tag command to label the most recent commit:
$ git tag v.0.0.0
Or if we like, we can create an “annotated” tag complete with a text message:
$ git tag -a v.0.0.0 -m "This is the initial state of my source code"
For more on tagging, see https://git-scm.com/book/en/v2/Git-Basics-Tagging
How do I…?
Protect files from being tracked (e.g. .log or .bak files)
git add * is very convenient but if we want to prevent some files from being included in that broad scope, we can leverage the .gitignore file.
Change a tracked file name
The mv command both renames a file in the file system and stages the change for the next commit:
$ git mv <old> <new>
Delete a tracked file
The rm command stages a file for removal, and also deletes the file in the file system:
$ git rm <file>
Unstage a file added incorrectly
To unstage a file, either of these commands work. “restore –staged” is the new way:
$ git reset HEAD <file%gt; $ git restore --staged <file>
Replace a staged file with a more up-to-date version
If you make a second edit to a file after you’ve already staged it, just stage it again to replaced the staged copy:
$ git add <file>
Revert just one file
To discard changes in the working directory, either of these commands work:
$ git checkout -- <file> $ git restore <file>
Delete multiple files using a wildcard spec
This command removes files from staging, and also escapes the wildcard character, which is necessary:
$ git rm --cached \*.log
Find out what tags I have
$ git tag
Next up, Part 2: Branching.