\documentclass[twoside,anypage,draft,10pt]{report} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% Packages %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \usepackage[utf8]{inputenc} \usepackage[T1]{fontenc} \usepackage{amsmath} \usepackage{amssymb} \usepackage{makeidx} \usepackage{graphicx} \usepackage{fourier} \usepackage{float} \raggedbottom \usepackage{array} \usepackage{multirow} \usepackage{gensymb} % Just for the degree symbol \usepackage{ccicons} % Creative Commons icons; now we can delete an image \usepackage{lettrine} % Drop caps \usepackage{wrapfig} % Let's wrap some images \usepackage{hanging} % For hanging indents in a script \usepackage{fancyvrb} % Use line numbers with code samples \usepackage{fvextra} % Break lines inside Verbatim environment: \usepackage{enumitem} % Control spacing in lists \usepackage{setspace} % Better control over line-spacing \usepackage{nicefrac} % Use nice fractions \usepackage[bottom]{footmisc} % Keep the footnotes at the bottom of the page \usepackage{tabto} % Use tab stops when we need to (especially in footnotes) \usepackage{microtype} % Make things neater. Thanks /u/-LeopardShark- \usepackage{tabularray} % Easy tables \usepackage[]{FiraSans} % sans-serif font; https://tug.org/FontCatalogue/firasansregular \usepackage[]{footmisc} \usepackage{ninecolors} \usepackage{setspace} \usepackage{tikz} \usepackage[obeyDraft, textcolor=red2, bordercolor=red, backgroundcolor=white, textsize=small]{todonotes} \usepackage{varwidth} %\usepackage{showframe} %\renewcommand*\ShowFrameColor{\color{red}} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% To-do list %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% Indices %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \usepackage{imakeidx} \makeindex[intoc] %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% Line Spacing %%%%%%%%%%%%%%%%%%%%%%%%%%%%% \setstretch{1.1} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% Commands %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \graphicspath{{images/}} % Where are our images? \usepackage{multicol} % Include two- or three-column sections %\counterwithout{footnote}{chapter} % Stop resetting the footnote count after each chapter \NumTabs{18} % Define 18 tab stops (at 1/4" intervals) [tabto package] \raggedbottom % Don't force text to fill page \setlength{\belowcaptionskip}{4pt} % Adjust space between caption and figure %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% Document Setup%%%%%%%%%%%%%%%%%%%%%%%%%%%% \usepackage{geometry} \geometry{ paperheight=11in, paperwidth=8.26in, heightrounded, inner=1.75in, outer=1.50in, textheight=9.00in, top=1.00in, } %\addtolength{\topmargin}{0.4in} % Adjust and bottom margin %\addtolength{\textheight}{-0.75in} % Adjust the bottom margin %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% Page Headers%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \usepackage{fancyhdr} \pagestyle{fancy} \fancyhf{} \fancyhead[LE,RO]{Page \thepage} \fancyhead[RE,LO]{A Git Primer} % \cfoot{Page \thepage} % \renewcommand{\footrulewidth}{0.5pt} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% Chapter Title Spacing %%%%%%%%%%%%%%%%%%%% \usepackage{titlesec} \titleformat {\chapter} % command [display] % shape {\normalfont\huge\bfseries} % format {\chaptertitlename\ \thechapter} % label {20pt} % sep {\Huge} % before code [{\color{green6} \hrule height 1pt width \textwidth}{\color{green8} \hrule height 4pt width 0.5\textwidth}] % after code \titlespacing* {\chapter} % command {0pt} % left margin {0pt} % before sep - vertical space before title {50pt} % after sep - separation between title and text % [] % right sep %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% Custom Macros %%%%%%%%%%%%%%%%%%%%%%%%%%%% % Make a nice border and box for the tops of our examples \newcommand\klab[3]{\vspace{#1}\noindent{}\hrulefill\fbox{\texttt{~#2~}}\hrulefill\vspace{#3}} % Add an \hrule with space above and below \newcommand\krule[2]{\vspace{#1}\hrule\vspace{#2}} % Make hrefs easier (must load package hyperref} \newcommand\kref[2]{\href{#1}{{\texttt{#2}}}} % Rotate text in tables easier % https://tex.stackexchange.com/questions/89115/how-to-rotate-text-in-multirow-table \newcommand\krot[3]{\parbox[t]{#1}{\multirow{#2}{*}{\rotatebox[origin=c]{90}{#3}}}} % Make diversions easier (and uniform!) \newcommand\kdivb[2]{ \medskip \hrule \medskip \noindent{}\textbf{#1} \vspace{#2mm} \begin{multicols}{2} } \newcommand\kdive[1]{ \end{multicols} \vspace{#1mm} \hrule \medskip } %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% Include URLS %%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Be sure to load this package last % [hidelinks option to hide big red box. Thanks /u/0b0101011001001011 \usepackage[hidelinks]{hyperref} % Inlcude URLs, but load this package last %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% Document Information %%%%%%%%%%%%%%%%%%%%% \author{Kenneth John Odle\\kenneth.odle@tutanota.com} \title{ {\fontsize{28}{0}\selectfont A Git Primer}\\ {\fontsize{12}{0}\selectfont for Coders and Creatives}\\ {\fontsize{10}{0}\selectfont Typeset in \LaTeX{}}\\ {\fontsize{10}{0}\selectfont v. 0.3.0} \\ \todo[inline]{Update version number before release} \todo[inline]{Remember to take this out of ``draft'' mode before publishing} } %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% Let's get it started %%%%%%%%%%%%%%%%%%%%% \begin{document} \maketitle \section*{Impressum} \thispagestyle{plain} \pagenumbering{gobble} % turn off page numbers \vspace{40mm} \copyright\the\year{} Kenneth John Odle \vspace{20mm} \noindent{}This document is formatted to print well on both letter and A4 size paper. Printing on A4 paper will result in slightly wider top and bottom margins than you see in the digital document, and printing on letter-size paper will result in slightly wider left and right margins than you see in the digital document. \vspace{10mm} \noindent{}This document is typeset in \LaTeX{} using the \texttt{report} class to allow the use of chapters. Three of the more important packages in this document are \texttt{titlesec}, \texttt{fancyvrb}, and \texttt{tabularray}. The \texttt{titlesec} package proves a large number of options for formatting items such as chapter and section headings. The layout of the chapter titles (including the green rules that separate the chapter title from the following content) have been created with this package. The \texttt{fancyvrb} package provides the best environment for code samples, including the ability to add line numbers, placing frames and titles around code snippets (as seen in the ``doc\_a.txt Initial Contents'' snippet on \pageref{doc-aIC}), and breaking long lines. The \texttt{tabularray} package is, hands-down, the best package for creating tables on \LaTeX{} that is currently available. It provides a large number of easy to understand formatting options. \vspace{10mm} \noindent{}The version number of this document corresponds to a semantic versioning system. For more information, visit \kref{https://semver.org/}{https://semver.org/}. \tableofcontents \thispagestyle{empty} % hide page numbers on TOC \newpage \phantom{This is here just to make a blank page on the back of the TOC.} \thispagestyle{empty} % hide page numbers on the back of the TOC \pagenumbering{arabic} % turn page numbers back on \chapter{Introduction} \setcounter{page}{1} Git is version control software. That is, it allows you to record and track changes to a set of files over time. You can then compare different revisions or even revert some files or the entire project back to a previous version. \section{What Git Can Do For You} Git is great if you are a software developer, because as you work you make a \textit{lot} of changes to your code. It's also great if you are a writer, because you can experiment as much as you want and not have to worry about losing or overwriting something. Git also allows you to experiment easily without worrying about losing your current work by creating and doing your experimental work on a \textit{branch}. If you like the experimental work, you can merge it into your main branch, or if you decide you don't like it, you can delete it. But more about that later. If you are just getting started in your career in programming, Git will have a lot of benefits for you. It can streamline your coding process, help you avoid losing work (and thus hours), make it easier to collaborate with others, and also give you a place to show off your work when you are looking for a job. If you are a writer rather than a coder, Git still has a lot to offer you as well. Revisions are a stock in trade for writers, as are experiments, and Git makes those things easily managed. Then too, because Git requires you to use text files (more about that later), you can focus on your writing without having to use any sort of ``distraction-free'' word processing program. Git makes experimenting both fun \textit{and} manageable, but most importantly of all, Git gives you \textit{control} over your work. \section{Git Concepts} If this is your first exposure to version control software you'll make faster progress if you understand some of the basic concepts. If you are coming to Git from a different version control software like Subversion or Mercurial, then many of these concepts will be familiar to you, although they will probably have different names and slightly functions. Keep in mind that all of these technologies work differently, so you may have to retrain your brain to follow a different workflow. \paragraph{Concept One: Git exists in both time and space.} This is true of just about all version control software, or at least all the different types I am aware of. \paragraph{Concept Two: The basic time unit of Git is a \textit{commit}.} A commit is simply a snapshot of where your project stands at any given moment. When you make a commit, it's like taking a picture of your project at that particular moment. \paragraph{Concept Three: The basic space unit of Git is a \textit{repository}.} All those commmits have to exist somewhere, and a repository is just a place where all those commits exist. Repositories (or ``repos'' for short) can be \textit{local}—that is, they exist on your computer only—or they can be \textit{remote}—meaning that can live on other computers somewhere else. That ``somewhere else'' is usually a publicly available server. You can create your own or you can get an account at some place like Gitlab or GitHub, which are privately run for-profit companies, or at someplace like Codeberg,\footnote{\kref{https://codeberg.org/}{https://codeberg.org/}} which is run by a non-profit entity. You can work with a local repository only, or you can decide to work with one or more remote repositories. The choice is up to you. \paragraph{Concept Four: Repositories are multi-dimensional.} If you make a series of commits to a repository, it will be linear in nature. This is perfectly ordinary. But you may get to a point where you want to experiment with something and you're not sure whether you'll like the new version or the old version better. Rather than commit that new version, which overrides the original version, you can \textit{branch} and have both versions existing at the same time. A branch is basically a copy of a repository at this point in time (i.e., from the last commit). You can then switch between branches and test things out. \paragraph{Concept Five: Git works best with text-based files\index{files, text-based}} Anything that has a \texttt{.txt}, \texttt{.html}, \texttt{.css}, \texttt{.php}, etc. extension is easy to track through Git. There's no reason that you can't add binaries, such as images, pdfs, Microsoft Word files, or LibreOffice files. (This document does include at least one image file, for example.) Because they are binaries, Git won't be able to tell you the difference between versions. \section{Git Clients} Git is a command line based technology. Yes, there are GUIs (Graphical User Interfaces) out there for Git, and if you are on Windows or macOS, you may find them useful. You can see a fairly comprehensive list at \kref{https://git-scm.com/book/en/v2/Appendix-A:-Git-in-Other-Environments-Graphical-Interfaces}{https://git-scm.com/book/en/v2/Appendix-A:-G\\it-in-Other-Environments-Graphical-Interfaces}. In general, I advise against using any type of GUI with Git. For one thing, Git is fairly easy to manage from the command line, so using a GUI just adds a level of abstraction that you don't really need. For another, the command line is forever, but GUIs come and go. If your GUI gets to a point where it's development is discontinued, or it decides to adopt a subscription model that you can't afford, you're in trouble. Finally, a GUI can also obscure what Git is actually doing, meaning that you might end up with less understanding of Git than you would develop by working on the command line. \section{Assumptions} That said, this document assumes that you are familiar with working on the command line in whatever OS you are accustomed to. You do not have to be an expert with it (that comes with time) but you should know how to open a terminal window, enter commands, and interpret whatever feedback you get. I work in Linux, so the commands and system responses you see here are from that environment, as are any file paths you will see. If you work in Windows or maxOSX, you will need to adjust parameters accordingly. \chapter{Local Repositories} Repositories are the basic space unit of Git. You can have as many of them as you want, both locally and remotely. Most people only have a single local repository, so let's start there. Assuming you have a folder full of files you want to track using Git, open a terminal window in that location and type \texttt{git init}. Congratulations! You now have a local Git repo! What has happened is that Git has created an invisible directory (\texttt{.git}) that it will use to store the metadata and database for your project. Do \textbf{not} delete this folder! Technically, the \texttt{.git} directory is the actual repository. You will often hear people refer to the folder that contains your working files along with the \texttt{.git} directory as a repo. It's best to think of the directory with your working files as your ``working directory'' and the \texttt{.git} directory as the repository. (Be aware that not everybody makes this distinction, though.) What we are lacking at this point is a basic time unit, because we haven't made any commits yet. All we have are files in our working directory. To make a commit that tracks what our project looks like here right here right now, we need to \textit{stage} our files by using the \texttt{git add} command. You can do this a couple of different ways: \begin{itemize} \item We can list each file one by one (i.e., \texttt{git add file1.txt file2.txt}). \item We can use the \texttt{*} wildcard (i.e., \texttt{git add *}) which will \textit{not} add invisible files. \item We can use the \texttt{-A} switch (i.e., \texttt{git add -A}) which \textit{will} add invisible files. \end{itemize} Before you stage files, though, it's a good idea to examine the status of your project. The command for that is \texttt{git status}. \section{Examining the Status of Your Project} Running Git status is pretty simple. It's just: \input{include/status} The status command is going to tell you three very important things: \begin{enumerate} \item How your current branch relates to your remote branch (if it exists). \item Changed files that you have already added to a commit. \item Untracked files that you have not yet added to a commit. \end{enumerate} A typical output from \texttt{git status} might look something like this: \begin{Verbatim}[frame=lines, numbers=left, xleftmargin=5mm, framesep=3mm, breaklines=true, label=\fbox{Typical Output from git status}] On branch main Your branch is up to date with 'ogit/main'. Changes to be committed: (use "git restore --staged ..." to unstage) modified: file1.txt Untracked files: (use "git add ..." to include in what will be committed) file2.txt file3.txt \end{Verbatim} The first two lines indicate that so far, nobody has made changes to your remote repository (which in this case is called ``ogit'') if you have one. (See the next chapter for more details about remote repositories.) This is typical if you are the only person working on this project, but you may see something different if other people have pushed changes to the remote. We'll talk about this later. It then shows files that you have staged under the ``Changes to be comitted:'' list. Notice that if you have committed a file accidentally (which can happen if you are using wildcards), Git is nice and provide the command you need to reverse that change (\texttt{git restore}). Finally, it shows you \textit{untracked} files. In other words, these are files that have been created or edited since the last commit, but have not yet been added to a new commit. Do you \textit{want} to track those untracked files? If you do, go ahead and add them using the \texttt{git add} command. If not, add them to the \texttt{.gitignore} file. \section{Ignoring Files} Suppose that you have files in your repository that you \textit{don't} want Git to keep track of. Perhaps they are just notes to yourself that you will later delete, or some test files will not be a permanent part of this project. In such a case, you can use an ignore file to tell Git to not worry about those files. The ignore file is an invisible file named \texttt{.gitignore} in your working directory. (Invisible files and directories always start with a period.) You can list individual files, or you can use wildcards to match multiple files. For example: \begin{itemize}[noitemsep] \item An asterisk (\texttt{*}) will match any number of characters except a forward slash. Using \texttt{*.ps} will cause Git to ignore any files that have a \texttt{.ps} extension in the current directory. \item A question mark (\texttt{?} will match a single character except a forward slash. Using \texttt{fo?.txt} will cause Git to ignore both \texttt{foa.txt} and \texttt{fob.txt}, but not \texttt{fogg.txt} in the current directory. \item A forward slash (\texttt{/}) serves as a directory separator. Using \texttt{foo/} will cause Git to ignore all the files in the \texttt{foo} directory. \item Blank lines don't match anything, so you can use them as separators for readability. \item Any line starting with a \texttt{\#} is a comment, so you can remind yourself of why you are ignoring something. \end{itemize} Keep in mind that your Git installation may be configured differently than the general guidelines above, so it's always best to test out your \texttt{.gitignore} file by running \texttt{git status} first. \section{Committing Staged Files} Now that you've added your files, they are considered to be \textit{staged}, which means that they are ready to commit. You can make a commit now, or you can modify or create new files, and then add them as well. The choice is yours—Git doesn't penalize you either way. Personally, I prefer to make many smaller commits to avoid losing data (and metadata). If you're happy with the files you've staged, we can now commit them by using \texttt{git commit -m ""}. Note that you have to add a commit message. This can be anything you like, but it helps to make it something that will be useful down the road like ``updated chapter three''. You'll get some miscellaneous messages about what Git is doing and then it is done. You've created your first commit, and all of your staged files are now committed. \section{How to View Commits} The entire point of Git is that any work you commit is never lost, so that if you delete something that you later decide you want back, it's just a matter of going back to one of those earlier commits, getting the information that you need, copying it, returning to your current version, and pasting the information back in. Fortunately, Git has plenty of ways of viewing your earlier commits. The most straightforward way (and probably the least useful, as well) is to simply view the log: \input{include/gitlog} which will give you output similar to this: \begin{Verbatim}[frame=lines, numbers=left, xleftmargin=5mm, framesep=3mm, breaklines=true, label=\fbox{Output of git log}] commit 162bfc0fcb2f8399985e6f7eab8503a2c227f2a3 (HEAD -> main, ogit/main) Author: Kenneth Odle Date: Sat Jan 25 14:56:02 2025 -0500 Removed section on bash aliases (beyond the scope) commit 0d9e1fee1de24951cabd928a3c2bc85aee355f02 Author: Kenneth Odle Date: Fri Jan 24 14:28:07 2025 -0500 Added information about workflows \end{Verbatim} In this example, each commit is identified by a unique SHA-1 hash (the forty characters appearing after the word ``commit'', followed by the author, their email, the date and time the commit was made, and finally, the commit message. Notice that the first commit is also labeled with \texttt{(HEAD -> main, ogit/main)}, showing that this commit is the latest commit. Git will show you a screenful of information at a time. You can use the down arrow on your keyboard to view more, and press the ``q'' key on your keyboard to break out of the command. I said that this is probably the least useful way of viewing commits because if your project has a lot of commits, you will have to scroll through a lot of information to find what you are looking for, unless it was in a very recent commit. If you want to see how many commits you have, you can use the \texttt{rev-list} command: \input{include/revlist} This will simply return a number indicating the number of commits, and thus how many screenfuls of information you may need to scroll through to find data from an early commit. However, you can use some options with \texttt{git log} to get just the information you need. For example, you the \texttt{--pretty=oneline} option to show only the SHA hash and the description for each commit on a single line. \input{include/gitlogoneline} which will produce output like this: \begin{Verbatim}[frame=lines, numbers=left, xleftmargin=5mm, framesep=3mm, breaklines=true, label=\fbox{Output of git log with pretty=oneline option}] 162bfc0fcb2f8399985e6f7eab8503a2c227f2a3 (HEAD -> main, ogit/main) Removed section on bash aliases (beyond the scope) 0d9e1fee1de24951cabd928a3c2bc85aee355f02 Added information about workflows d37d470c95a7d02a76a4cabea22960a74cf8a2cc Added inline to-do items 02d40255da4acde637c953fda7727f09ba8ca091 Updated changelog, version number 43e59f77dee0b2ee42a44838ab561236273383a9 Significant addtions to branching chapter \end{Verbatim} The \texttt{--pretty} option has a lot of configuration options that you can experiment with to get just the information you need. But if you have a lot of commits, the simplest option is just to send all that output to a text file, which you can open with a text editor and then search. For example, this command: \input{include/gitprettyoptions} sends the output of that command to a file (\texttt{log.txt}), the first few lines of which look like this: \begin{Verbatim}[frame=lines, numbers=left, xleftmargin=5mm, framesep=3mm, breaklines=true, label=\fbox{}] 2025-01-25 162bfc0 Kenneth Odle Removed section on bash aliases (beyond the scope) 2025-01-24 0d9e1fe Kenneth Odle Added information about workflows 2025-01-22 d37d470 Kenneth Odle Added inline to-do items 2025-01-22 02d4025 Kenneth Odle Updated changelog, version number 2025-01-22 43e59f7 Kenneth Odle Significant additions to branching chapter \end{Verbatim} Here we get the date of the commit (in YYYY-MM-DD format), followed by an abbreviated commit hash, the name of the comitter (important if you have more than one person working on this project), and finally the commit description. \section{Examining Earlier Commits} Now that you know how to find earlier commits, you need to know how to revert to one. To do that, you simply \texttt{checkout} the earlier commit, using just enough of the SHA-1 hash to be identifiable: \input{include/gitcheckoutcommit} In this case, this would take me back to the ``Significant additions to branching chapter'' commit. To get back to the latest commit, we simply checkout our current branch, which in this case is ``main'': \input{include/gitcheckoutmain} Before checking out an earlier commit, you should make sure to add and commit any changes you have made since your last commit, to avoid losing any recent changes. (You can also use \texttt{git stash save} command to save your current work as a patch, then use \texttt{git stash apply} to re-apply your local changes. The exact details on this are beyond the scope of this document, however.) Of course, the easiest way to view older commits and examine them is by using a \textit{remote} repository, because their graphical interface is far easier to navigate. \chapter{Remote Repositories} Remote repositories make it possible to share your work and to collaborate with others. You can do all sorts of things locally, but at some point, you're probably going to want to put your work out there either to share or collaborate, or to just show off. \section{Getting a Remote Repository} If you set up a remote repo a some place like GitHub, or you find a repo somewhere that you would like to work with on your own, you can \textit{clone} that remote repo like this: \input{include/clone} For example, if you wanted to get a copy of the Apollo 11 Guidance Computer source code because you happen to be planning a trip to the moon of your own,\footnote{I was delighted to find out that this was available on GitHub. I first learned about this in the Volume Thirty-Eight, Number Four issue of \textit{2600} in an article called ``Supply and Demand, Apollo 11, and GitHub''.} you would just type \texttt{git clone https://github.com/chrislgarry/Apollo-11}. Git would create a directory called ``Apollo-11'' and clone a local version of that entire repository into it. If you want to see the remotes attached to this repo, you can just type \texttt{git remote -v}. In this case, it would show you something like this: \begin{Verbatim}[frame=lines, numbers=left, xleftmargin=5mm, framesep=3mm, breaklines=true, label=\fbox{Output of git remote -v with one remote repository}] origin https://github.com/chrislgarry/Apollo-11 (fetch) origin https://github.com/chrislgarry/Apollo-11 (push) \end{Verbatim} Of course, those remote repositories don't belong to you, so you can't push any changes you make to them. What you can do is create your own remote repo on a Git-hosting system. I've created one on Codeberg at \kref{https://codeberg.org/kjodle/Apollo-11}{https://codeberg.org/kjodle/Apol\\lo-11}. To add that remote to my local repo, I will use this command: \input{include/remoteadd} And running the \texttt{git remote -v} command again shows that I have two different remotes: \begin{Verbatim}[frame=lines, numbers=left, xleftmargin=5mm, framesep=3mm, breaklines=true, label=\fbox{Output of git remote -v with two remote repositories}] berg https://codeberg.org/kjodle/Apollo-11 (fetch) berg https://codeberg.org/kjodle/Apollo-11 (push) origin https://github.com/chrislgarry/Apollo-11 (fetch) origin https://github.com/chrislgarry/Apollo-11 (push) \end{Verbatim} I named my remote ``berg'', to distinguish it from the ``origin''. I need to get rid of those remotes on GitHub, since I can't push any changes to them anyway. To do that I'll use this command: \input{include/remoteremove} Running \texttt{git remote -v} again shows that I now just have the remote on my own website: \begin{Verbatim}[frame=lines, numbers=left, xleftmargin=5mm, framesep=3mm, breaklines=true, label=\fbox{Output of git remote -v after removing a remote repository}] berg https://codeberg.org/kjodle/Apollo-11 (fetch) berg https://codeberg.org/kjodle/Apollo-11 (push) \end{Verbatim} Are we ready to upload this code from my local repository to my remote repo? Not yet. Let's see what our local branches are named by running \texttt{ git branch}, which gives us this: \begin{Verbatim}[] * master \end{Verbatim} In this case, I only have a single branch, which is named ``master''. It also has an asterisk because it's the current branch. The problem here is that Codeberg always names branches ``main''. So I need to change that branch name by running \input{include/branchrename} Running \texttt{ git branch} again confirms that our branch has been renamed: \begin{Verbatim}[] * main \end{Verbatim} \section{Pushing Changes to a Remote Repository} Okay, I have a local repository, I have a remote repository attached to that local repository, and the current branch on both repos have the same name. It's time to move that code from the local repository to the remote one. For that I'll use \texttt{git push} . Since the remote is named ``berg'' and the branch is named ``main'', the full command looks like this: \input{include/push} Git thought for a moment, and produced this output: \begin{Verbatim}[frame=lines, numbers=left, xleftmargin=5mm, framesep=3mm, breaklines=true, label=\fbox{Output of git push command}] Enumerating objects: 3414, done. Counting objects: 100% (3414/3414), done. Delta compression using up to 4 threads Compressing objects: 100% (1077/1077), done. Writing objects: 100% (3414/3414), 3.01 MiB | 1.69 MiB/s, done. Total 3414 (delta 2327), reused 3414 (delta 2327), pack-reused 0 remote: . Processing 1 references remote: Processed 1 references in total To https://codeberg.org/kjodle/Apollo-11 * [new branch] main -> main \end{Verbatim} That really did take only about a second to push 3.1 MiB\footnote{That's not a typo. MiB stands for a \texttt{mebibyte}.} of data. One of the nice things about Git is that it is remarkably fast. If you visit that original repository that I cloned on GitHub, you'll see that it has 547 commits. If you then visit the repository I created at \kref{https://codeberg.org/kjodle/Apollo-11}{https://codeberg.org/\\kjodle/Apollo-11}, you'll see that it also has 547 commits. This is one of the unique features of Git: when you clone that remote repository, you are getting \textit{everything} associated with that repo. Other version control applications just checkout the most recent version. Hence the term ``clone'' rather than ``checkout''. As we can see from this example, you can have multiple remotes. I can create a remote repository on GitHub, clone it to my local machine, then create a remote somewhere else and add that remote to my local repo. To keep both remotes up to date with local changes, you'll need to push twice, once with \texttt{git push remote1 main} and again with \texttt{git push remote2 main}. If you are working on a project that others are also working on, running \texttt{git status} may show you something like this: \begin{Verbatim}[frame=lines, numbers=left, xleftmargin=5mm, framesep=3mm, breaklines=true, label=\fbox{Atypical Output from git status}] On branch main Your branch is behind 'origin/main' by 1 commit, and can be fast-forwarded. (use "git pull" to update your local branch) \end{Verbatim} If you are collaborating with other people on a project, you may see different messages here. Others working on the project may have made changes that will conflict with your changes and could be difficult or impossible to reconcile. Always communicate with other project owners and use branching to prevent this. \subsection{A Note About \texttt{git push} Syntax} This command sometimes confuses new users. To help you understand what is happening here, this is the basic structure of this command: \begin{figure}[H] \centering \begin{tikzpicture} \draw (0,0) rectangle (.8,1.4); \node at (0.4,.7) {git}; \end{tikzpicture} \raisebox{5mm}{\begin{Huge}$ \Rightarrow $\end{Huge}} \begin{tikzpicture} \draw (0,0) rectangle (1.2,1.4); \node at (0.6,.7) {push}; \end{tikzpicture} \raisebox{5mm}{\begin{Huge}$ \Rightarrow $\end{Huge}} \begin{tikzpicture} \draw (0,0) rectangle (3.4,1.4); \node at (1.7,.7) [align=center] {\begin{varwidth}{3cm}\begin{center}where I'm pushing (i.e., the name of the remote repository)\end{center}\end{varwidth}}; \end{tikzpicture} \raisebox{5mm}{\begin{Huge}$ \Rightarrow $\end{Huge}} \begin{tikzpicture} \draw (0,0) rectangle (3.4,1.4); \node at (1.7,.7) [align=center] {\begin{varwidth}{3cm}\begin{center}what I'm pushing (i.e., the name of the current branch)\end{center}\end{varwidth}}; \end{tikzpicture} \end{figure} \chapter{Branches} If you want to experiment, the best way to do that is to create a \textit{branch}. There are two steps to this: \begin{enumerate} \item Create a branch using \texttt{git branch }. \item Move to that branch using \texttt{git branch checkout }. \end{enumerate} Of course, there's a shortcut to this. You can use \input{include/checkout} \noindent{}which creates a branch called ``branchname'' and moves you to it automatically. This is the point where you can experiment and have fun on this branch without worrying about messing up your main branch. If you like the changes that you made on this branch, you can then go back to your main branch (\texttt{git checkout main}) and \textit{merge} those changes. \input{include/merge} It's always a good idea to clean up after ourselves. If we don't need that experimental branch any more, we can delete it with \texttt{git branch -d }. In reality, things are rarely going to be this simple, unless you are only making very basic changes to a branch. You'll possibly get all sorts of error messages or warning messages, and may get confused or even scared. Unfortunately, dealing with those error messages is beyond the scope of this document, but the nice thing about Git is that most of the solutions you need are easily found on the web. \section{A Basic Branching Example} To get a basic understanding of how branching works in Git, let's start with a simple example. We'll assume that we have a single document called \texttt{doc\_a.txt}. It only contains two lines: \label{doc-aIC} \begin{Verbatim}[frame=lines, numbers=left, xleftmargin=5mm, framesep=3mm, breaklines=true, label=\fbox{doc\_a.txt Initial Contents}] This is line A1. This is line A2. \end{Verbatim} Let's go ahead and commit those using the following set of commands: \input{include/branch001} Notice that we don't have a remote repository at this point, so all we are doing is making commits. Running \texttt{git status} gives us this output: \begin{Verbatim}[frame=lines, numbers=left, xleftmargin=5mm, framesep=3mm, breaklines=true, label=\fbox{Output from git status}] On branch main nothing to commit, working tree clean \end{Verbatim} Let's suppose we want to make some edits in this file, but we're not sure if we're going to keep them—we're just testing. To do that, we'll create a new branch called ``testbranch'' with this command: \input{include/branch002} Git immediately gives us this message: \begin{Verbatim}[] Switched to a new branch 'testbranch' \end{Verbatim} Now we're going to add a new line to \texttt{doc\_a.txt} so it looks like this: \label{doc-aC2} \begin{Verbatim}[frame=lines, numbers=left, xleftmargin=5mm, framesep=3mm, breaklines=true, label=\fbox{doc\_a.txt New Contents}] This is line A1. This is line A2. This is line B1. \end{Verbatim} Now if we run \texttt{git status}, we'll see this: \begin{Verbatim}[frame=lines, numbers=left, xleftmargin=5mm, framesep=3mm, breaklines=true, label=\fbox{Output of git status with Changes to Project}] On branch testbranch Changes not staged for commit: (use "git add ..." to update what will be committed) (use "git restore ..." to discard changes in working directory) modified: doc_a.txt no changes added to commit (use "git add" and/or "git commit -a") \end{Verbatim} Again, Git provides us with helpful information here. It's telling us that we are on ``testbranch'' and not our main branch, it tells us that we have changes in a file, and that we have yet not committed those changes. What it's not telling us is what those changes are. To do that, we use the \texttt{git diff} command: \input{include/gitdiff} Which gives us this output: \begin{Verbatim}[frame=lines, numbers=left, xleftmargin=5mm, framesep=3mm, breaklines=true, label=\fbox{Output of git diff}] diff --git a/doc_a.txt b/doc_a.txt index ea9c135..01b52bf 100644 --- a/doc_a.txt +++ b/doc_a.txt @@ -1,2 +1,3 @@ This is line A1. This is line A2. +This is line A3. \end{Verbatim} In most terminals, this output will be color-coded, which is helpful on the fly, but I've added line numbers here to help us. Let's take this line by line to understand what Git is telling us. \begin{itemize} \item Line 1 (\texttt{diff --git a/doc\_a.txt b/doc\_a.txt}) shows us that we are examining two different versions of the same file. Git is calling the original version ``a'' and the new version ``b'' \item Line 2 (starting with ``\texttt{index}'') is meta data about the files, and is not terribly useful. \texttt{100644} shows that this is a normal file, rather than an executable one (which would be \texttt{100755}) or a symbolic link (which would be \texttt{120000}). \item Lines 3 and 4 show that Git is assigning a minus sign (-) to the ``a'' version of the file and a plus sing (+) to the ``b'' version of the file, which it will use starting in line 6. \item Line 5 is a \textbf{chunk header}. Git is not going to show you the entire contents of your file, but rather just the chunks that have differences. (Except in our example, which is a very small file.) \begin{itemize} \item The chunk header starts and ends with \texttt{@@}. \item ``\texttt{-1, 2}'' is actually three separate pieces of information. Git is telling us that it is going to show us 2 lines, starting at line 1, from the ``a'' version of our file (because of the minus sign at the beginning). \item ``\texttt{+1, 3}'' is again three separate pieces of information. Git is telling us that it is going to show us 3 lines, starting at line 1, from the ``b'' version of our file (because of the plus sign at the beginning). \end{itemize} \item Lines 6-8 are the lines that are different. Notice that line 8 starts with a plus sign, meaning that this line appears in version ``b'' only. \end{itemize} Let's make a couple of other changes, and see how this output changes. First, let's \textit{delete} the first line (``This is line A1.''). Second, let's create a new file (which we'll call \texttt{doc\_b.txt}) which will contain a single line of text: ``This is line B1.'' Running \texttt{git diff} now gives us slightly different output: \begin{Verbatim}[frame=lines, numbers=left, xleftmargin=5mm, framesep=3mm, breaklines=true, label=\fbox{Output of git diff}] diff --git a/doc_a.txt b/doc_a.txt index 01b52bf..505be23 100644 --- a/doc_a.txt +++ b/doc_a.txt @@ -1,3 +1,2 @@ -This is line A1. This is line A2. This is line A3. \end{Verbatim} This is similar to before, but now we are seeing that line 6 now has a minus sign in front of it, because that line only exists in the original version of that file. But it doesn't show us any information about \texttt{doc\_b.txt} because that file is completely new. How does this test branch compare to our main branch? First, let's add both files (\texttt{git add -A}) and make a commit (\texttt{git commit -m "commit message"}). Now we can ask Git to tell us the difference between these two branches using this command: \input{include/gitdiffbranch} \begin{Verbatim}[frame=lines, numbers=left, xleftmargin=5mm, framesep=3mm, breaklines=true, label=\fbox{Output of git diff main testbranch}] diff --git a/doc_a.txt b/doc_a.txt index ea9c135..505be23 100644 --- a/doc_a.txt +++ b/doc_a.txt @@ -1,2 +1,2 @@ -This is line A1. This is line A2. +This is line A3. diff --git a/doc_b.txt b/doc_b.txt new file mode 100644 index 0000000..3fc1659 --- /dev/null +++ b/doc_b.txt @@ -0,0 +1 @@ +This is line B1. \end{Verbatim} Lines 2-8 tell us about ``doc\_a.txt'' and lines 9-15 tells us about ``doc\_b.txt''. Notice that line 12 is telling us that the ``a'' version of ``\texttt{doc\_b.txt}'' (that is, the version that exists in the main branch) is ``\texttt{/dev/null}'' which is Git's way of telling us that this file does not exist at all in the main branch. In fact, line 14 shows us \texttt{-0,0} which means that Git is showing us zero lines starting at line zero from the ``a'' version of this file. \section{Merging and Deleting Branches} Once you have a branch that you're happy with, it's time to \textit{merge} those changes into your main branch. In our example above, this would be easily accomplished with the following commands: \begin{Verbatim}[frame=lines, numbers=left, xleftmargin=5mm, framesep=3mm, breaklines=true, label=\fbox{Merging a branch}] git checkout main git merge testbranch \end{Verbatim} The first command makes sure that you are on your main branch. The second one merges the changes from your test branch into the main. In reality, it may not be as simple as this, because there may be conflicts between some of the changes on the test branch and your main branch. (This often happens when you have also made changes to the main branch in the meantime. Git does have a method to detect this, and it will pause the merge process, tell that you have a conflict in certain files, and instruct you to fix the conflicts and then commit the result before attempting the merge again. If you want to delete a local branch, you can do so with this command: \begin{Verbatim}[] git branch -d \end{Verbatim} The \texttt{-d} option will only delete the branch if you've already merged it, so this is a handy way to prevent mistakes if you want to ensure you've merged this branch. If, on the other hand, you decided not to merge this branch and just want to get rid of it, you would use this command: \begin{Verbatim}[] git branch -D \end{Verbatim} In this case, the capital \texttt{-D} is an alias for \texttt{--delete --force} which will delete a branch regardless of its merged status. If you have pushed this branch to a remote repository and would like to delete it from there, you can use: \begin{Verbatim}[] git push --delete \end{Verbatim} \section{Other Notes about Branching} Note that what you see in your directory (both in a text editor and in your GUI) will depend upon which branch you have checked out. For example, in our branching example, we will first check out the \texttt{main} branch and then do a file listing: \input{include/gitcheckoutmain&ls} which will then give us this output: \begin{Verbatim}[] doc_a.txt \end{Verbatim} Here's a screen capture of our online version, but if you've cloned this locally and are looking at the \texttt{main} branch, you should see something like this: \vspace{0.5\baselineskip} \frame{\includegraphics[scale=0.75]{gitea-checkout-main}} \vspace{\baselineskip} If we checkout the \texttt{testbranch} branch and then do a file listing: \input{include/gitcheckouttestbranch&ls} we get this output: \begin{Verbatim}[] doc_a.txt doc_b.txt \end{Verbatim} Again, here's a screen capture of our online version, which should resemble what you see in your GUI if you've cloned this: \vspace{0.5\baselineskip} \frame{\includegraphics[scale=0.75]{gitea-checkout-testbranch}} \section{Uses of Branching} It's fairly easy to see how branching can be useful when you're writing code, because it allows you to experiment without worrying about introducing errors into your main body of code. But branching is also useful for purposes other than writing code. Let's look at a couple of those. \subsection{Technical Writing} For better or for worse, most technical writing—standard operating procedures, work instructions, etc.—gets done in Microsoft Word. Word has the advantage that most companies already have a license for it and also that most people can easily understand its visual interface. The major problem with word is that formatting is always an issue. You can use and adapt the built-in paragraph and character styles, but unless everyone in your company who is responsible for writing documents understands how paragraph and character styles work, and even if they do, there is no guarantee that they will use whatever defaults you have set up the way they were intended. The biggest problem, though, is that Microsoft Word is not easy to use for experimentation.\footnote{It does have a ``Track Changes'' feature, but that means that you are experimenting in your original document, or you have to create an experimental document that you later use to overwrite your original document.} A far better option for technical writing is to use a text-based editor and compiler, such as \LaTeX{}\footnote{See \kref{https://www.latex-project.org/}{https://www.latex-project.org/}.} or DITA\footnote{The Darwin Information Typing Architecture; see \kref{https://dita-lang.org/}{https://dita-lang.org/} for more information.}. Both of these technologies use plain text files to create documents (\texttt{.tex} and \texttt{.xml} files, respectively) and so are easy to track through Git. Because they are text-based documentation systems, updating work instructions or standard operating procedures is a simple matter of creating a new branch to create and perfect that update. When you get to a point where everybody (production, QA/QC, management, et al.) is satisfied with the update, all that's needed to update the current document is to return to the main branch and merge that experimental branch. If you are using an online repository, you can also issue a new release which shows that this is the latest version of your document. It's even possible to have different teams work on their own versions of an update by each creating their own branch. You can then decide which parts of each branch you want to incorporate into the new branch. \subsection{Creative Writing} ``What if?'' is the big question behind most fiction. If you are a creative writer and are using plain text files to write your drafts\footnote{And you should, really. Working in plain text files means that you have to focus on your story in a mostly distraction free environment. All the text decoration can come later.} Working in a branch allows you to experiment with a story's structure to your heart's content without having to worry about whether you are going to create a mess of your main story outline. \chapter{Collaborating With Yourself — A Guide for Creatives} I mentioned earlier that you could use Git if you're a writer to keep track of changes to projects, provided you were willing to work with text files. My goal here is to provide a basic workflow for doing that. I'm going to assume a few things: \begin{enumerate}[noitemsep] \item You have a remote repository somewhere on a host (like GitHub or your own website). \item You write all your stories in plain text files in a local repo. \item Your repository host allows you to edit files on their website. (Codeberg uses Gitea\footnote{\kref{https://gitea.com/}{https://gitea.com/}} which allows this option, and other Git hosts have similar options.) \end{enumerate} The advantage to the workflow I'm describing here is that you can work on your files even if you are not working from your normal machine. Thanks to family medical issues, I sometimes spend a lot of time in hospital waiting rooms and I bring my Chromebook with me. I can edit my files on the web, and then pull down changes to my main laptop (which never leaves my house) when I get home. This is how I do it. I'll physically go to wherever we are for the day (library, caf\'e, hospital waiting room, etc.) and login to my repository host. I can edit files online using this button: \begin{center} \noindent{}\frame{\includegraphics[scale=0.75]{gitea-online-edit}} \end{center} At the end of the day, I'll home and go into my local repo, open a terminal in that directory and use the \texttt{git pull} command: \input{include/pull} What does \texttt{git pull} do? It's a combination of two Git commands: \texttt{fetch} and \texttt{merge}. \texttt{git fetch} gets the change history of the tracked remote and branch, whereas \texttt{git merge} combines the current branch with the specified branch. My local repository will now look like My remote repository. I can write to my heart's content, push those changes, and call it a day. If I'm back at the hospital waiting room again some time later, I can just repeat the process. \chapter{Next Steps} \section{Workflows} Git makes it easy to be methodical in your work. It's therefore useful to have workflows in mind when working with Git, especially when you are using remote repositories. You have a choice of two basic approaches: create your local repository first, or create your remote repository first. Both have their advantages. \subsection{Remote Repository First} In this approach, you create your remote repository first, and then clone it using this command: \input{include/clone} By default, your remote repository will be named \texttt{origin}, but you can change this by using the \texttt{--origin} (or the short \texttt{-o} version) option: \input{include/cloneorigin} The main advantage of this approach is that you can begin pushing your work to your remote repository immediately, which may be important if you have people who are waiting to see it or collaborate with you on it. If you don't start pushing right away, at least they know where your work will eventually be. \subsection{Local Repository First} In this approach, you create your local directory first using \texttt{git init}. You then create a remote repository when it is convenient to you, and add that remote using this command: \input{include/gitadd} This approach has numerous advantages. You can begin making commits at once, and then push everything to your remote only when you are ready. This also allows you to experiment with a number of different projects and then make only those public that you feel are high enough quality to share with the world. This approach has one main disadvantage, however. Because your work exists only on your local machine, if something happens to your computer, you will lose all of your work. This can be mitigated by making regular backups. \section{README.md} If you pull or clone a remote repository, you may notice a file called \texttt{README.md}. This is a text document written in Markdown (hence the \texttt{.md} file extension) which appears on the front page of the online repo. You can include images and links, as well as licensing information. (I have a quick guide to Markdown syntax at \kref{https://codeberg.org/kjodle/markdown_syntax}{https://codeberg.org/kjodle/m\\arkdown\_syntax}.) \section{Forks and Pull Requests} These things aren't a part of Git, but they are something that is offered by GitHub and other repository hosts, so I just want to give the briefest of descriptions here for clarity and completion. To \textit{fork} a remote repository is to make a copy of it so that you can contribute to this project. You fork somebody else's project, clone it locally, make your changes, push those changes to your remote repo, and then make a \textit{pull request}, which alerts the owner of the original repository that you have changes you'd like them to incorporate into their project. They can then pull those changes in, or they can ignore them. \chapter{Summary of Git Commands} One of my favorite aspects of Git is that it's fairly intuitive to understand and start using right out of the box, but it's also robust enough to meet the needs of large teams and organizations. What I've done in the following table is to summarize the commands I've used in this primer, along with examples where appropriate. \begin{longtblr} [ caption = {Summary of Git Commands}, label = {tb:gitcommsum}, % theme = {custom1} ]{ width = {\textwidth}, colspec = { X[20,l] X[80,l] }, hlines = {0.5pt,solid}, vline{1,3} = {0.5pt,solid}, rows = {5mm, m, rowsep=1.5pt}, rowhead = 1, cells = {font=\sffamily\fontsize{8pt}{11pt}\selectfont}, row{1} = {font=\bfseries}, } Command & Purpose {\& Example, if applicable} \\ \texttt{git -{}-version} & Displays the version of git installed on your system \\ \texttt{git add} & {Stages (i.e., adds) files to a commit \\ \texttt{git add file1 file2} } \\ {\texttt{git add -A} \\ \texttt{git add --all}} & Stages (i.e., adds) all files (including invisible ones) to a commit \\ \texttt{git add *} & Stages (i.e., adds) all visible files to a commit \\ \texttt{git branch} & Show all branches (the current branch is labeled with an asterisk) \\ \texttt{git branch -{}-show-current} & Show only the current branch \\ \texttt{git clone} & {Clones a remote repository locally \\ \texttt{git clone} } \\ \texttt{git commit} & {Commits stages files \\ \texttt{git commit -m} ``'' } \\ \texttt{git fetch} & Get the change history of a specific tracked remote and branch \\ \texttt{git init} & {Creates a local git repository \\ \texttt{git init} } \\ \texttt{git log} & Show the commit logs. Will show a lot of information unless you include options to limit the number of logs displayed. \\ \texttt{git merge} & Incorporate changes from the named commits into the current branch \\ \texttt{git pull} & A combination of \texttt{fetch} and \texttt{merge} \\ \texttt{git push} & {Pushes a commit from a local repo to a remote repo \\ \texttt{git push} } \\ \texttt{git remote} & {Show only the names of remote repos \\ \texttt{git remote} } \\ \texttt{git remote -v} & {Show both the names and URLs of remote repos \\ \texttt{git remote -v} } \\ \texttt{git rev-list} & List commit hashes in reverse chronological order. (This command is more useful if you specify options.) \\ \texttt{git status} & Show which files have been staged and which files are waiting to be staged \\ \texttt{git status -s} & As above, but in short form \\ \texttt{git status -u} & As above, but only show untracked files \\ \texttt{git status -v} & Verbose output (default) \\ \end{longtblr} \chapter*{Changelog} \addcontentsline{toc}{chapter}{Changelog} \begin{longtblr} [ % caption = {}, label = none, % theme = {custom1} ]{ width = {\textwidth}, colspec = { X[1,l] X[2,l] X[7,l] }, hlines = {0.5pt,solid}, vline{1,4} = {0.5pt,solid}, rows = {5mm, m, rowsep=1.5pt}, rowhead = 1, cells = {font=\fontsize{9pt}{12pt}\selectfont}, row{1} = {font=\bfseries}, } Version & Release Date & Details \\ 0.1.0 & 17 August 2024 & Working version \todo[inline]{Update changelog before release} \\ 0.2.0 & 21 August 2024 & Miscellaneous updates \\ 0.3.0 & 22 January 2025 & Expanded branching chapter \\ \end{longtblr} \listoftodos \end{document}