Add Git introduction
This commit is contained in:
parent
3465376d9a
commit
f11bc5f603
@ -35,7 +35,7 @@ files that we'll describe as we go.
|
||||
To get an idea of how source packages are structured, we'll start with a
|
||||
fairly simple package, ``lxqt-about``::
|
||||
|
||||
aaron@pkg-builder:~/lubuntu-dev/lxqt-about$ tree
|
||||
aaron@pkg-builder:~/vmshare/pkg/lxqt-about$ tree
|
||||
.
|
||||
├── aboutdialog
|
||||
│ ...
|
||||
@ -707,5 +707,833 @@ from there and build it.
|
||||
``lxqt-about`` deb file, alongside several other files.
|
||||
|
||||
That's it! If the above worked, you now have a working packaging environment!
|
||||
We're now ready to move past system setup, and start learning how packaging
|
||||
works.
|
||||
We're now ready to move past system setup, and start learning how to do Debian
|
||||
packaging.
|
||||
|
||||
Git essentials
|
||||
--------------
|
||||
|
||||
.. NOTE::
|
||||
If you already have a decent working knowledge of Git, you can skim this
|
||||
section and only focus on the parts that have to do with Debian packages.
|
||||
|
||||
If you're working with Debian packages, you are almost certainly going to have
|
||||
to work with Git. Git is, in essence, a tool for keeping track of changes that
|
||||
are made to files in a directory. As changes are made to the directory,
|
||||
developers use Git to take snapshots of what they changed and how. This is
|
||||
very useful in both software development and packaging, because:
|
||||
|
||||
* Keeping track of changes in this way allows you to look at how things
|
||||
changed in the past if needed.
|
||||
* If something important is lost in the course of changes, you can get it
|
||||
back out of Git's history.
|
||||
* If some changes break everything, you can revert them and go back to a
|
||||
previous commit.
|
||||
* Each time someone changes something, their identity is attached to that
|
||||
change, meaning you can determine who changed what, and when.
|
||||
* If multiple people are changing the same file at the same time, Git can keep
|
||||
track of those changes independently, then merge them together later so that
|
||||
nothing is lost.
|
||||
|
||||
Because of the large number of uses Git has, it can be a tricky tool to get
|
||||
used to. It has far too many features to fully explain in this guide, so we're
|
||||
only going to go over the basics here. If you want to learn more about Git
|
||||
than this guide covers, you should read the free
|
||||
`Pro Git e-book <https://git-scm.com/book/en/v2>`__. Git also has a number of
|
||||
manual pages you can browse through, see ``man git``.
|
||||
|
||||
Repos, commits, branches, tags, and remotes
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
The primary purpose of Git is manipulating Git *repositories*. A repository
|
||||
(or "repo" for short) is nothing more than a directory full of files, with a
|
||||
hidden ``.git`` subdirectory in it. The files in this directory are just
|
||||
regular files, like you're already used to working with. All of Git's state
|
||||
(the repo history and whatnot) is stored in the ``.git`` directory. Git is
|
||||
intended to be used from the command line, and provides a number of commands
|
||||
for repo manipulation. These commands usually affect whatever repo you are
|
||||
"in". For instance, if ``$HOME/my-project`` is a Git repo, you are "in" the
|
||||
``my-project`` repo if your current working directory is ``$HOME/my-project``
|
||||
or any subdirectory underneath it.
|
||||
|
||||
As you make changes to a Git repository, you will want to *commit* your
|
||||
changes from time to time. A Git commit is a bit of data that records what
|
||||
files changed, what lines in those files changed, how those lines changed, and
|
||||
who changed them. Each commit has a unique ID bound to it, so you can
|
||||
unambiguously refer to any commit in the repository. When you create a new
|
||||
commit, that's called "committing" a change. Commits can be *checked out*,
|
||||
meaning that the files in the repository will be changed to reflect what the
|
||||
repo looked like at the time that commit was made.
|
||||
|
||||
.. NOTE::
|
||||
Git commits can track both large and small changes, but generally it's most
|
||||
useful if you try to make each Git commit correspond to one logical change
|
||||
in a project. For instance, if you need to change the version number of a
|
||||
package, fix an issue that prevents the package from building, make the
|
||||
README clearer, and introduce a patch to change default settings, each of
|
||||
those changes should go into separate commits. On the other hand, if you
|
||||
need to fix a common typo that occur in ten files, it's fine to put all of
|
||||
those fixes in one commit.
|
||||
|
||||
Being able to keep track of changes as they're made is useful, but it isn't
|
||||
enough for most projects. You might have multiple people making changes to a
|
||||
project at the same time. You might want to make some experimental changes
|
||||
without having to do a bunch of messy reverts if they don't work out. You
|
||||
might even need to maintain different versions of the same project as if they
|
||||
were separate sub-projects. To handle these scenarios, Git allows you to
|
||||
create *branches* within a repo. Each branch is essentially a separate
|
||||
timeline, tracking one or more commits entirely separate from other commits.
|
||||
If one commit is made to one branch and another commit is made to another
|
||||
branch, each branch will only "see" the commit that was made on them. If you
|
||||
want to take all of the commits from one branch and integrate them into
|
||||
another, you can *merge* branches. Each branch has a *tip*, which is the
|
||||
commit most recently made to that branch. Similar to commits, branches can be
|
||||
checked out. Whatever commit is on the tip of the checked-out branch will end
|
||||
up checked out when you do this. (Note that checking out a branch is *not*
|
||||
exactly the same as checking out the commit at the tip of a branch, we'll
|
||||
cover the differences further later.)
|
||||
|
||||
Every so often, you'll create a commit that is, for one reason or another,
|
||||
special. You may want to quickly look at this commit later, without having to
|
||||
analyze the repo to figure out where it's at. Git provides *tags* for marking
|
||||
these special commits. One common use of tags is to mark the last commit made
|
||||
before releasing a new version of a project. The tagged commit can then be
|
||||
used to look at the state the repo was in when that version of the project was
|
||||
released. Tags can be checked out too; checking out a tag is exactly identical
|
||||
to checking out the commit a tag is associated with.
|
||||
|
||||
All of the above features work locally, on your system. Again, a Git repo is
|
||||
nothing more than a directory with a hidden ``.git`` subdirectory. So what
|
||||
happens when you want to publish your changes for others to see? How do you
|
||||
receive changes from others? This is where Git remotes come into play. A Git
|
||||
remote is a server that has a copy of a Git repo on it. As you make changes to
|
||||
your copy of the repo, you can *push* a branch to the remote; this will send
|
||||
commits that you've created to the remote, which will then integrate those
|
||||
commits into a branch of its copy of the repo. If other people have made
|
||||
changes to a branch on the remote, and you want to download them, you can
|
||||
*pull* that branch. Last, but not least, if you want a copy of a Git repo you
|
||||
don't have yet, you can *clone* the repo from the remote.
|
||||
|
||||
Armed with an understanding of these concepts, you are now ready to work with
|
||||
Git.
|
||||
|
||||
Analyzing a Git repo
|
||||
^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Remember running ``git clone`` to download the ``lxqt-about-packaging``
|
||||
project earlier? (See "Testing the packaging environment" above if you don't
|
||||
remember this.) The ``git clone`` command *clones* a repository. That means we
|
||||
have a fully functional Git repo already downloaded, so let's take a closer
|
||||
look at it and see what's in there!
|
||||
|
||||
Ensure the ``lubuntu-dev`` window is open and the VM is running. Then open
|
||||
QTerminal, and change to the ``lxqt-about-packaging`` directory::
|
||||
|
||||
cd $HOME/vmshare/pkg/lxqt-about-packaging
|
||||
|
||||
Now that we're here, let's look at some basic info about the repo, and see if
|
||||
any changes have been made to it that haven't been comitted yet. To do this,
|
||||
run ``git status``. Assuming you haven't changed the repo since we ran the
|
||||
``sbuild`` command previously, you should see something like this::
|
||||
|
||||
On branch ubuntu/resolute
|
||||
Your branch is up to date with 'origin/ubuntu/resolute'.
|
||||
|
||||
nothing to commit, working tree clean
|
||||
|
||||
Let's break down what this means:
|
||||
|
||||
* One of the branches in this repo is called ``ubuntu/resolute``. This is the
|
||||
branch we are actively "on", meaning that all the files in the project's
|
||||
directory reflect Git's idea of the files on the ``ubuntu/resolute`` branch.
|
||||
If we make any changes to these files and commit them, our new commit will
|
||||
end up added to the ``ubuntu/resolute`` branch.
|
||||
* The ``ubuntu/resolute`` branch does not just exist on our machine, it also
|
||||
exists on the Git remote named ``origin``. To Git's awareness, our copy of
|
||||
``ubuntu/resolute`` matches ``origin``'s copy of ``ubuntu/resolute``.
|
||||
* All of the files in the repo match exactly what's been committed to the
|
||||
``ubuntu/resolute`` branch (well, all of the files Git cares about anyway,
|
||||
we'll look at that closer in a bit). We don't have any changes that need
|
||||
committed. (What we've been calling the "files in the repo", Git calls the
|
||||
"working tree".)
|
||||
|
||||
Most of this is straightforward, except... what is this remote named
|
||||
``origin``? Let's see what remotes we have::
|
||||
|
||||
git remote
|
||||
|
||||
Running this command should print the following::
|
||||
|
||||
origin
|
||||
|
||||
Well that's not particularly useful. Let's look at what the ``origin`` remote
|
||||
actually points to::
|
||||
|
||||
git remote get-url origin
|
||||
|
||||
This will output the following::
|
||||
|
||||
https://git.lubuntu.me/Lubuntu/lxqt-about-packaging.git
|
||||
|
||||
That's much more useful. The ``origin`` remote points to the
|
||||
``lxqt-about-packaging`` repo on Lubuntu's Gitea instance.
|
||||
|
||||
.. NOTE::
|
||||
When you clone a repository, Git automatically takes the URL you cloned the
|
||||
repo from, and turns it into the ``origin`` remote. You can have more than
|
||||
one remote in a repository, and if you spend enough time packaging you'll
|
||||
probably run into situations where being able to do this is useful, but for
|
||||
now we'll focus on managing a repo with just one remote.
|
||||
|
||||
Git repos generally are worked on by multiple people. Lubuntu's packaging
|
||||
repos are no exception; each packager needs to be able to upload their changes
|
||||
to a packaging repo after preparing the packaging for a Lubuntu component.
|
||||
For this reason, it's generally a good idea to download the latest changes to
|
||||
a repo before beginning work on it. Let's do that now, just in case someone's
|
||||
modified ``lxqt-about-packaging``::
|
||||
|
||||
git pull
|
||||
|
||||
If there were changes, you'll see some info about the download, that starts
|
||||
with something like this::
|
||||
|
||||
remote: Enumerating objects: 54, done.
|
||||
remote: Counting objects: 100% (54/54), done.
|
||||
remote: Compressing objects: 100% (29/29), done.
|
||||
remote: Total 54 (delta 26), reused 51 (delta 23), pack-reused 0 (from 0)
|
||||
Unpacking objects: 100% (54/54), 331.53 KiB | 1.03 MiB/s, done.
|
||||
From git.lubuntu.me:Lubuntu/lxqt-about-packaging
|
||||
Updating 98c3794..fe38a66
|
||||
Fast-forward
|
||||
debian/changelog | 1 +
|
||||
debian/control | 2 +-
|
||||
debian/copyright | 2 +-
|
||||
debian/watch | 11 ++++++-----
|
||||
4 files changed, 9 insertions(+), 7 deletions(-)
|
||||
|
||||
Exactly what Git shows here may vary, since it's showing a summary of the
|
||||
download process, the changes that were downloaded, whether they apply to the
|
||||
active branch or not, etc. For now we don't have to worry about most of this,
|
||||
we'll cover how to deal with the edge cases later.
|
||||
|
||||
Alternatively, if there weren't any changes, you'll see::
|
||||
|
||||
Already up to date.
|
||||
|
||||
Now that we have our repo up-to-date, let's look at some of the most recent
|
||||
commits and see what people have been doing lately::
|
||||
|
||||
git log
|
||||
|
||||
This will output something like this::
|
||||
|
||||
commit fe38a662e5c7e0c87d31a25097e9dc29dfe23554 (HEAD -> ubuntu/resolute, origin/ubuntu/resolute)
|
||||
Author: Aaron Rainbolt <arraybolt3@ubuntu.com>
|
||||
Date: Tue Nov 18 13:16:56 2025 -0600
|
||||
|
||||
Use debian/watch version 5 (taken from Debian's packages)
|
||||
|
||||
commit f90b89bffb8c04c1a0a9979cc02bd077a1d2deff (tag: ubuntu/2.2.0-0ubuntu1, origin/ubuntu/questing)
|
||||
Author: Aaron Rainbolt <arraybolt3@ubuntu.com>
|
||||
Date: Thu Jul 31 16:16:32 2025 -0500
|
||||
|
||||
Update build deps
|
||||
|
||||
commit 98c37947c4abdcda7487893cf15a3b73a26d3572
|
||||
Author: Aaron Rainbolt <arraybolt3@ubuntu.com>
|
||||
Date: Thu Jul 31 16:16:00 2025 -0500
|
||||
|
||||
Bump Standards-Version
|
||||
|
||||
commit 65c030aacf544aa46ca0c9159853e3da05edc3e2
|
||||
Author: Aaron Rainbolt <arraybolt3@ubuntu.com>
|
||||
Date: Thu Jul 31 16:15:30 2025 -0500
|
||||
|
||||
Update copyright file
|
||||
|
||||
commit 9f9ab07b6c8483ad890dda9b16f9883f6815a49d
|
||||
Author: Aaron Rainbolt <arraybolt3@ubuntu.com>
|
||||
Date: Thu Jul 31 16:14:31 2025 -0500
|
||||
|
||||
Bump version for new upstream release
|
||||
|
||||
You'll also notice your Bash prompt is gone, and instead your cursor is
|
||||
sitting directly after a ``:`` character. That's because you're in a *pager*,
|
||||
allowing you to scroll the Git log. You can scroll in any direction (including
|
||||
left and right) using the arrow keys, and can scroll up and down quickly using
|
||||
the Page Up and Page Down keys. To exit the pager and get back to a normal
|
||||
Bash prompt, press ``q``.
|
||||
|
||||
Now that we're out of the pager, let's look closer at what all this info
|
||||
means. You don't have to fully understand all of this yet, you can come back
|
||||
and reference this later.
|
||||
|
||||
* Each "section" (separated from adjacent sections by newlines) corresponds to
|
||||
a single commit.
|
||||
* Each commit has a unique ID (this is that long hexadecimal number you see
|
||||
after ``commit`` in each commit entry).
|
||||
* Each commit has an author, the person who actually wrote the changes that
|
||||
went into the commit. Authors are identified by name and email address.
|
||||
(This is why we configured your name and email into Git when we set up the
|
||||
packaging environment; this info will end up attached to commits you
|
||||
create.)
|
||||
* Each commit has a date. This is the exact date and time at which the commit
|
||||
was created.
|
||||
* Each commit has a *commit message*. Generally when you make changes to a
|
||||
repository, you want to document *what* you changed, and *why*. These
|
||||
records should be put into commit messages. Many repositories (especially
|
||||
Lubuntu's packaging repositories) just have one-line commit messages briefly
|
||||
summarizing what was done.
|
||||
* Some commits have one or more branches displayed next to them. These commits
|
||||
are on the tip of each respective branch. For instance, if we were to check
|
||||
out ``ubuntu/resolute``, we'd end up on commit
|
||||
``fe38a662e5c7e0c87d31a25097e9dc29dfe23554``.
|
||||
|
||||
.. NOTE::
|
||||
Commit IDs are ridiculously long, hard to type, and just about impossible
|
||||
to remember. To work around this, you can use the first several characters
|
||||
of a commit ID in place of a full commit ID in most instances. It's
|
||||
traditional to use the first seven or eight characters, since it's rare for
|
||||
two commits in the same repo to ever have the same first seven characters,
|
||||
and it's still short enough to be temporarily memorized and typed without
|
||||
too much trouble.
|
||||
|
||||
* Some commits also have *remote* branches displayed next to them. Remember
|
||||
when we saw ``origin/ubuntu/resolute`` earlier? That was referring to
|
||||
``origin``'s copy of ``ubuntu/resolute``. Well, we see it again here. We
|
||||
also see ``origin/ubuntu/questing``, which is ``origin``'s copy of
|
||||
the ``ubuntu/questing`` branch.
|
||||
* We can also see a tag, ``ubuntu/2.2.0-0ubuntu1``. This means that someone
|
||||
decided that commit ``f90b89b`` should have this "name" associated with it.
|
||||
In Lubuntu's packaging repos, we use tags to keep track of which commits
|
||||
correspond to which package version numbers. Whoever packaged ``lxqt-about``
|
||||
version ``2.2.0-0ubuntu1``, made this tag to say "if you check out
|
||||
``f90b89b``, you will see the packaging that I uploaded to Ubuntu when I
|
||||
created version 2.2.0-0ubuntu1 of this package."
|
||||
* Finally, what's this ``HEAD`` thing? In Git, the "head" is a pointer that
|
||||
tracks whatever commit you are currently "on". In this instance, HEAD is on
|
||||
commit ``fe38a66``. The ``->`` in ``HEAD -> ubuntu/resolute`` means that
|
||||
HEAD is currently *attached* to the branch ``ubuntu/resolute``. That means
|
||||
that if you make a new commit, not only will ``HEAD`` move to the new
|
||||
commit, the commit will also be added to the ``ubuntu/resolute`` branch,
|
||||
thus changing the tip of the branch.
|
||||
|
||||
Now that we see what's going on with the log, let's take a look at the
|
||||
repository's branches. We saw earlier that ``origin`` has an
|
||||
``ubuntu/questing`` branch, so let's list off all the branches in the
|
||||
repository and see what all we have::
|
||||
|
||||
git branch
|
||||
|
||||
This will output::
|
||||
|
||||
* ubuntu/resolute
|
||||
|
||||
Well that can't be right! There's an ``ubuntu/questing`` branch, so where is
|
||||
it? To answer that question, we need to think a bit more about how Git works.
|
||||
|
||||
* Every developer has their own copy of the repo, and the remote has a copy
|
||||
too.
|
||||
* Every developer can modify their repo as they see fit. They have to manually
|
||||
upload and download changes that have been made to the repo on the remote.
|
||||
* Developers can create and upload new branches.
|
||||
* Therefore, **the remote repo might have branches your repo doesn't have.**
|
||||
|
||||
Every time you download changes from the remote using ``git pull``, Git finds
|
||||
out what branches the remote has available, downloads any commits associated
|
||||
with them, and keeps track of those for you. However, it doesn't change the
|
||||
branches in your repo. This makes it so that if you and someone else both make
|
||||
a branch with the same name, you don't end up with serious problems the next
|
||||
time both of you pull changes from the remote. Instead, Git keeps track of
|
||||
your repo's branches and the remote repo's branches *separately*.
|
||||
|
||||
When you see ``origin/ubuntu/resolute``, that's because there's actually a
|
||||
branch named ``origin/ubuntu/resolute``. You also have a branch named
|
||||
``ubuntu/resolute``, and that branch happens to be *tracking*
|
||||
``origin/ubuntu/resolute``. That means that when changes to
|
||||
``origin/ubuntu/resolute`` are downloaded, ``ubuntu/resolute`` gets updated
|
||||
with those changes. It also means if you change ``ubuntu/resolute``, and
|
||||
upload your changes, those changes will end up in ``origin/ubuntu/resolute``.
|
||||
It's a two-way sync.
|
||||
|
||||
With this in mind, we can better understand why ``ubuntu/questing`` is
|
||||
missing; we don't have a branch named ``ubuntu/questing`` yet. We do know that
|
||||
the ``origin`` remote has such a branch though. So let's see what branches
|
||||
``origin`` has::
|
||||
|
||||
git branch -r
|
||||
|
||||
This will output quite a bit more information::
|
||||
|
||||
origin/HEAD -> origin/ubuntu/resolute
|
||||
origin/backports/focal
|
||||
origin/backports/jammy
|
||||
origin/backports/mantic
|
||||
origin/ci/stable
|
||||
origin/ci/unstable
|
||||
origin/ubuntu/cosmic
|
||||
origin/ubuntu/disco
|
||||
origin/ubuntu/eoan
|
||||
origin/ubuntu/focal
|
||||
origin/ubuntu/groovy
|
||||
origin/ubuntu/hirsute
|
||||
origin/ubuntu/impish
|
||||
origin/ubuntu/kinetic
|
||||
origin/ubuntu/lunar
|
||||
origin/ubuntu/mantic
|
||||
origin/ubuntu/noble
|
||||
origin/ubuntu/oracular
|
||||
origin/ubuntu/plucky
|
||||
origin/ubuntu/questing
|
||||
origin/ubuntu/resolute
|
||||
|
||||
We see that ``origin`` has a whole lot of branches, including the elusive
|
||||
``origin/ubuntu/questing`` one we're looking for. There's also
|
||||
``origin/HEAD``, which can be safely ignored.
|
||||
|
||||
.. NOTE::
|
||||
If you're wondering what ``origin/HEAD`` is, see
|
||||
`<this answer on Stack Exchange https://superuser.com/a/1192881/1734781>`__.
|
||||
|
||||
Now, the question is, how do we add one of these remote branches to our repo?
|
||||
To do this, we'll simply *check out* the branch::
|
||||
|
||||
git checkout ubuntu/questing
|
||||
|
||||
This will output the following::
|
||||
|
||||
branch 'ubuntu/questing' set up to track 'origin/ubuntu/questing'.
|
||||
Switched to a new branch 'ubuntu/questing'
|
||||
|
||||
And now if we run ``git branch`` again, we'll see::
|
||||
|
||||
* ubuntu/questing
|
||||
ubuntu/resolute
|
||||
|
||||
Perfect! Now we have ``ubuntu/questing`` in our repo. We've also switched to
|
||||
the ``ubuntu/questing`` branch, meaning our repo's working tree matches the
|
||||
commit at the tip of ``ubuntu/questing``. To illustrate, let's look at a file
|
||||
in the repository that will be different in ``ubuntu/questing`` and
|
||||
``ubuntu/resolute``::
|
||||
|
||||
cat debian/watch
|
||||
|
||||
This will output the following::
|
||||
|
||||
version=4
|
||||
opts="searchmode=plain, \
|
||||
pgpsigurlmangle=s/$/.asc/, \
|
||||
uversionmangle=s/(\d+\.\d+\.\d+).*/$1/" \
|
||||
https://api.github.com/repos/lxqt/@PACKAGE@/releases https:\/\/github.com\/lxqt\/@PACKAGE@\/releases\/download\/@ANY_VERSION@\/@PACKAGE@-@ANY_VERSION@.tar.xz
|
||||
|
||||
We'll cover what all of this means once we get into Debian packaging itself.
|
||||
For the time being though, let's switch back to ``ubuntu/resolute`` and see
|
||||
what happens::
|
||||
|
||||
git checkout ubuntu/resolute
|
||||
|
||||
This will output the following::
|
||||
|
||||
Switched to branch 'ubuntu/resolute'
|
||||
Your branch is up to date with 'origin/ubuntu/resolute'.
|
||||
|
||||
Now let's look at the ``debian/watch`` file again::
|
||||
|
||||
cat debian/watch
|
||||
|
||||
This will output the following::
|
||||
|
||||
Version: 5
|
||||
Template: GitHub
|
||||
Owner: lxqt
|
||||
Project: @PACKAGE@
|
||||
Download-Url-Mangle: s%https://api.github.com/repos/([^/]+)/@PACKAGE@/git/refs/tags/@ANY_VERSION@%https://github.com/$1/@PACKAGE@/releases/download/$2/@PACKAGE@-$2.tar.xz%g
|
||||
Pgp-Mode: auto
|
||||
|
||||
That looks entirely different than what we saw a bit ago! What happened there?
|
||||
We can find out what happened, by taking a look at the Git history. First,
|
||||
let's find out who made the changes to this file::
|
||||
|
||||
git blame debian/watch
|
||||
|
||||
This will show us a line-by-line breakdown of the file, indicating what
|
||||
commits changed each line in the file, who made them, and when they made
|
||||
them::
|
||||
|
||||
fe38a662 (Aaron Rainbolt 2025-11-18 13:16:56 -0600 1) Version: 5
|
||||
fe38a662 (Aaron Rainbolt 2025-11-18 13:16:56 -0600 2) Template: GitHub
|
||||
fe38a662 (Aaron Rainbolt 2025-11-18 13:16:56 -0600 3) Owner: lxqt
|
||||
fe38a662 (Aaron Rainbolt 2025-11-18 13:16:56 -0600 4) Project: @PACKAGE@
|
||||
fe38a662 (Aaron Rainbolt 2025-11-18 13:16:56 -0600 5) Download-Url-Mangle: s%https://api.github.com/repos/([^/]+)/@PACKAGE@/git/refs/tags/@ANY_VERSION@%https://github.com/$1/@PACKAGE@/releases/download/$2/@PACKAGE@-$2.tar.xz%g
|
||||
fe38a662 (Aaron Rainbolt 2025-11-18 13:16:56 -0600 6) Pgp-Mode: auto
|
||||
|
||||
See the ``fe38a662``? That's a partial commit ID! If we look back at the
|
||||
output of ``git log`` from earlier, we can see the full commit ID, and
|
||||
corresponding commit message::
|
||||
|
||||
commit fe38a662e5c7e0c87d31a25097e9dc29dfe23554 (HEAD -> ubuntu/resolute, origin/ubuntu/resolute)
|
||||
Author: Aaron Rainbolt <arraybolt3@ubuntu.com>
|
||||
Date: Tue Nov 18 13:16:56 2025 -0600
|
||||
|
||||
Use debian/watch version 5 (taken from Debian's packages)
|
||||
|
||||
Now that we know who changed the file and when, let's see what their changes
|
||||
looked like. Each Git commit corresponds to a *state* the repo was in when the
|
||||
commit was made, so we can't simply say "show me commit XYZ". What we *can*
|
||||
say is "show me everything that changed between commit ABC and commit XYZ".
|
||||
Furthermore, Git allows us to refer to the commit *before* a particular commit
|
||||
by adding a caret (``^``) after a commit ID. That is, ``fe38a662^`` refers to
|
||||
the commit immediately *before* ``fe38a662``. Now that we have two commits to
|
||||
compare to each other, we can tell Git to show us what changed between those
|
||||
commits::
|
||||
|
||||
git diff fe38a662^ fe38a662
|
||||
|
||||
This will output the following::
|
||||
|
||||
diff --git a/debian/copyright b/debian/copyright
|
||||
index 7b74a60..6ee271d 100644
|
||||
--- a/debian/copyright
|
||||
+++ b/debian/copyright
|
||||
@@ -11,10 +11,10 @@ License: LGPL-2.1+
|
||||
|
||||
Files: debian/*
|
||||
Copyright: 2021-2025 Lubuntu Developers <lubuntu-devel@lists.ubuntu.com>
|
||||
- 2022 ChangZhuo Chen (陳昌倬) <czchen@debian.org>
|
||||
2014-2019 Alf Gaida <agaida@siduction.org>
|
||||
2015-2021 Andrew Lee (李健秋) <ajqlee@debian.org>
|
||||
2025 Aaron Rainbolt <arraybolt3@ubuntu.com>
|
||||
+ 2022-2025 ChangZhuo Chen (陳昌倬) <czchen@debian.org>
|
||||
License: LGPL-2.1+
|
||||
|
||||
License: LGPL-2.1+
|
||||
diff --git a/debian/watch b/debian/watch
|
||||
index a544020..4070de7 100644
|
||||
--- a/debian/watch
|
||||
+++ b/debian/watch
|
||||
@@ -1,5 +1,6 @@
|
||||
-version=4
|
||||
-opts="searchmode=plain, \
|
||||
-pgpsigurlmangle=s/$/.asc/, \
|
||||
-uversionmangle=s/(\d+\.\d+\.\d+).*/$1/" \
|
||||
- https://api.github.com/repos/lxqt/@PACKAGE@/releases https:\/\/github.com\/lxqt\/@PACKAGE@\/releases\/download\/@ANY_VERSION@\/@PACKAGE@-@ANY_VERSION@.tar.xz
|
||||
+Version: 5
|
||||
+Template: GitHub
|
||||
+Owner: lxqt
|
||||
+Project: @PACKAGE@
|
||||
+Download-Url-Mangle: s%https://api.github.com/repos/([^/]+)/@PACKAGE@/git/refs/tags/@ANY_VERSION@%https://github.com/$1/@PACKAGE@/releases/download/$2/@PACKAGE@-$2.tar.xz%g
|
||||
+Pgp-Mode: auto
|
||||
|
||||
We won't go into all the intricacies of the diff format used here. Suffice to
|
||||
say, lines prefixed with a ``-`` are lines that were *removed*, and lines
|
||||
prefixed with a ``+`` are lines that were *added*. In this case we can see
|
||||
that ``debian/watch`` got completely rewritten. We also see that in
|
||||
``debian/copyright``, ChangZhuo Chen was moved to the bottom of the
|
||||
``Files: debian/*`` section, and the ``2022`` copyright reference was changed
|
||||
to ``2022-2025``. Why exactly this was done, only the committer knows, but
|
||||
that's what was done. The commit log conveniently lists Aaron's email, so now
|
||||
you can now email Aaron Rainbolt and ask him why he did this.
|
||||
|
||||
.. NOTE::
|
||||
The reason Aaron (me) made this change was because the ``debian/watch``
|
||||
file in this package was previously broken, and the Debian LXQt Team's
|
||||
``debian/watch`` file was working. I copied their file, and plugged it into
|
||||
Lubuntu's packaging to get things to work right. The Git repo for Debian's
|
||||
``lxqt-about`` package listed ChangZhuo Chen as the author of the new watch
|
||||
file contents, so I moved their copyright info to the bottom and updated
|
||||
their copyright date accordingly.
|
||||
|
||||
.. WARNING::
|
||||
If you're security-conscious, you might be asking yourself, "what's to stop
|
||||
me from pretending to be Aaron or anyone else when I make a change to the
|
||||
repo?" The answer is, **nothing prevents this by default.** Impersonating
|
||||
others in Git logs is very easy. This is part of why projects don't hand
|
||||
out Git commit access to just anyone; it would be too easy to do something
|
||||
malicious and make someone else look like they were at fault. Even this
|
||||
isn't bullet-proof though, a contributor might become malicious, or someone
|
||||
might hack the server that hosts the remote Git repo. Thankfully, there is
|
||||
a good way to make it impossible for others to impersonate you, which is to
|
||||
PGP-sign your Git commits. More on that later.
|
||||
|
||||
This is all well and good if we just want to analyze the differences between
|
||||
individual commits. But what if we want to diff something else? Perhaps
|
||||
someone recently pushed five commits to the ``ubuntu/resolute`` branch, and we
|
||||
want to see what the repo looked like before and after their changes. There
|
||||
are a few ways we can do this:
|
||||
|
||||
* The most obvious way is to use ``git log`` to identify the commits we want
|
||||
to compare, and then compare them with ``git diff``. For instance, if the
|
||||
commit HEAD is on is ``12345678``, and the commit immediately before the
|
||||
batch of changes is ``abcdefab``, we can compare them with
|
||||
``git diff abcdefab 12345678``.
|
||||
* As a shortcut, if we want to refer to the HEAD commit, we don't have to type
|
||||
out the full commit ID HEAD is on. We can just use ``HEAD``, like so:
|
||||
``git diff abcdefab HEAD``.
|
||||
* We can also combine ``HEAD`` with ``^``. If we want to compare the commit
|
||||
HEAD is on with the commit before it, we can use ``git diff HEAD^ HEAD``.
|
||||
This only goes back one commit though, and we want to go back five, so...
|
||||
* You can actually use ``^`` multiple times to go back more than one commit!
|
||||
To compare the commit that is five commits back from HEAD, with the commit
|
||||
HEAD is on, we can use ``git diff HEAD^^^^^ HEAD``.
|
||||
* Typing ``^`` over and over can become cumbersome. As a shortcut, you can use
|
||||
``~N`` after a commit ID, where ``N`` is the number of commits to go
|
||||
backward. This works with ``HEAD`` too, so we can use
|
||||
``git diff HEAD~5 HEAD``. This will give the exact same results as
|
||||
``git diff HEAD^^^^^ HEAD``.
|
||||
|
||||
It's possible to diff "things" other than commits also, so long as those
|
||||
"things" point at commits. Branches and tags can be compared to other
|
||||
branches, other tags, commits IDs, or HEAD. Git calls all of these things
|
||||
"refs". Diffing two refs will diff the commits the refs point to.
|
||||
|
||||
Modifying a Git repo
|
||||
^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Most of the above covers how to look at existing commits and refs. What if we
|
||||
want to make some changes to the repo and commit them? Let's try doing that
|
||||
now, by changing the ``debian/control`` file. Open the file in a text editor
|
||||
such as Featherpad, by running ``featherpad debian/control`` Scroll to the
|
||||
bottom of the file, then change the description for ``lxqt-about-l10n`` to
|
||||
say::
|
||||
|
||||
The about screen for LXQt
|
||||
.
|
||||
This package contains the l10n files needed by the lxqt-about.
|
||||
It also contains an extra line in the description for qwerty.
|
||||
|
||||
(You will be adding the last line to the description here. Mind the extra
|
||||
space at the start of each line, those are intentional. We'll cover those
|
||||
further when we get into packaging itself.)
|
||||
|
||||
.. NOTE::
|
||||
You can use whatever text editor you want, but once you start doing a lot
|
||||
of packaging, you'll probably want to learn how to use a text editor that
|
||||
runs directly in the terminal. This is a lot more efficient than having to
|
||||
switch between a terminal window and a GUI text editor. The editor
|
||||
generally recommended for Lubuntu development is Vim, which comes
|
||||
preinstalled on Lubuntu. You can get started with learning to use Vim by
|
||||
running ``vimtutor`` in a terminal window.
|
||||
|
||||
Save and close the file. Now let's see what Git thinks about what we've just
|
||||
done, by running ``git status``. It will output the following::
|
||||
|
||||
On branch ubuntu/resolute
|
||||
Your branch is up to date with 'origin/ubuntu/resolute'.
|
||||
|
||||
Changes not staged for commit:
|
||||
(use "git add <file>..." to update what will be committed)
|
||||
(use "git restore <file>..." to discard changes in working directory)
|
||||
modified: debian/control
|
||||
|
||||
no changes added to commit (use "git add" and/or "git commit -a")
|
||||
|
||||
Git sees that we modified the file, but claims that the changes we've made
|
||||
aren't "staged for commit". In order to allow users to break up large changes
|
||||
into multiple commits, Git uses the concept of a staging area (called the
|
||||
"index"). Changes made to a repo have to be "staged" before they can be
|
||||
committed, and when a new commit is made, only staged changes go into the
|
||||
commit. This means if you make two unrelated changes to different parts of the
|
||||
repo, you can stage one of those changes and commit it, while leaving the other
|
||||
change unstaged. Once the first commit is made, you can stage and commit the
|
||||
other change.
|
||||
|
||||
Changes can be staged by using ``git add``. You'll generally want to use
|
||||
``git add`` in one of three ways:
|
||||
|
||||
* To stage an individual file, use ``git add path/to/file``. For instance, to
|
||||
stage the changes we just made to ``debian/control``, you can use
|
||||
``git add debian/control``.
|
||||
* To stage all of the files that changed within a directory, use
|
||||
``git add path/to/dir/*``. You can stage the changes made to
|
||||
``debian/control`` using ``git add debian/*``. Note that this recurses into
|
||||
subdirectories; if ``debian/control`` and ``debian/upstream/metadata`` were
|
||||
both changed, ``git add debian/*`` would stage both those files.
|
||||
* Finally, to stage *all* changes made within the repo, use ``git add -A``.
|
||||
This is probably the way you'll use ``git add`` the most.
|
||||
|
||||
Now that we've staged the change, let's see what ``git status`` reports now::
|
||||
|
||||
On branch ubuntu/resolute
|
||||
Your branch is up to date with 'origin/ubuntu/resolute'.
|
||||
|
||||
Changes to be committed:
|
||||
(use "git restore --staged <file>..." to unstage)
|
||||
modified: debian/control
|
||||
|
||||
We're now ready to commit a change finally! As one might expect, changes are
|
||||
committed by using ``git commit``.
|
||||
|
||||
* The easiest way to use this command is to just run ``git commit``; a text
|
||||
editor will be opened, allowing you to write a description of the changes
|
||||
you've made. This is good for if you need to write a long, detailed
|
||||
explanation of what you've changed, but most of the time you won't need to
|
||||
do that.
|
||||
* If you only want a short description for the changes, you can give Git the
|
||||
description by using ``git commit -m 'description here'``.
|
||||
|
||||
Let's commit the change we just made, by running
|
||||
``git commit -m 'update lxqt-about-l10n description'``. You should now see
|
||||
something similar to the following::
|
||||
|
||||
[ubuntu/resolute 4686cc1] update lxqt-about-l10n description
|
||||
1 file changed, 1 insertion(+)
|
||||
|
||||
Congratulations, you have now committed your first change! If we look at
|
||||
``git status`` now, we'll see::
|
||||
|
||||
On branch ubuntu/resolute
|
||||
Your branch is ahead of 'origin/ubuntu/resolute' by 1 commit.
|
||||
(use "git push" to publish your local commits)
|
||||
|
||||
nothing to commit, working tree clean
|
||||
|
||||
This should all look familiar by now, except for the line
|
||||
``Your branch is ahead of 'origin/ubuntu/resolute' by 1 commit.`` This means
|
||||
that our copy of ``ubuntu/resolute`` has one commit in it that ``origin``'s
|
||||
copy of ``ubuntu/resolute`` doesn't have yet.
|
||||
|
||||
Let's see what happens if we create a new file in the repo. Make sure you're
|
||||
in the ``lxqt-about-packaging`` directory, and then create a file named
|
||||
``test.md`` with the following contents::
|
||||
|
||||
# Test file
|
||||
|
||||
This is a test file.
|
||||
|
||||
Save and close the file, then run ``git status`` again. You should see::
|
||||
|
||||
On branch ubuntu/resolute
|
||||
Your branch is ahead of 'origin/ubuntu/resolute' by 1 commit.
|
||||
(use "git push" to publish your local commits)
|
||||
|
||||
Untracked files:
|
||||
(use "git add <file>..." to include in what will be committed)
|
||||
test.md
|
||||
|
||||
nothing added to commit but untracked files present (use "git add" to track)
|
||||
|
||||
This is a bit different than what we saw earlier. That's because previously,
|
||||
we modified a file Git already knew about in this repo, namely
|
||||
``debian/control``. Git does not yet know that ``test.md`` is actually part of
|
||||
the repo, so it's considered *untracked*. Git treats untracked files and
|
||||
unstaged changes to tracked files in subtly different ways we'll investigate
|
||||
later, but for now, you can mostly treat untracked files the same way you'd
|
||||
treat any other modified file. We don't actually need to commit this file to
|
||||
continue learning how Git works, so go ahead and delete the file with
|
||||
``rm test.md``.
|
||||
|
||||
Inevitably, as you work on packaging, you are going to make mistakes, and
|
||||
inevitably, you're going to end up committing some of those mistakes. Let's
|
||||
look at the line we added to ``debian/control`` a bit ago::
|
||||
|
||||
It also contains an extra line in the description for qwerty.
|
||||
|
||||
This probably looked a bit strange to you. "qwerty" really doesn't describe
|
||||
what we're doing accurately. "testing" would be a better word to use. Go ahead
|
||||
and change ``qwerty`` to ``testing`` now, using Featherpad or your preferred
|
||||
text editor. Stage the change with ``git add -A`` when you're done.
|
||||
|
||||
Now, we *could* just add the fix as a new commit. However, in this instance,
|
||||
that's probably not the best thing to do since the commit exists only on your
|
||||
computer. No one else knows that we wrote "qwerty" when we meant "testing", so
|
||||
we can simply recreate the commit. To do that, use
|
||||
``git commit --amend --no-edit``. This will discard the previous commit, and
|
||||
create a new one that contains all of the changes from the previous commit
|
||||
plus all of the changes in the index. It will also preserve our commit message
|
||||
unchanged (that's what ``--no-edit`` does). If you want to change the commit
|
||||
message too (or if the only thing you want to change is the commit message),
|
||||
you can leave off ``--no-edit`` to get a commit message editor, or you can use
|
||||
``-m`` to pass a one-line commit message, just like you would when using ``git
|
||||
commit`` normally.
|
||||
|
||||
.. NOTE::
|
||||
I intentionally avoided saying that we're *changing* the commit here.
|
||||
Commits are immutable, and each commit links to the commit immediately
|
||||
behind it. This allows Git to provides a number of helpful features, but it
|
||||
also means that one shouldn't think in terms of "changing" a commit.
|
||||
|
||||
.. NOTE::
|
||||
``git commit --amend`` is useful for recreating the last commit. But what
|
||||
if we need to fix something from several commits ago? Because commits are
|
||||
linked together and immutable, we have to recreate the bad commit and every
|
||||
commit ahead of it. Git provides a utility for this, ``git rebase``, but
|
||||
you'll rarely need it and it is tricky to use, so we won't cover this yet.
|
||||
|
||||
Amending a commit is useful for fixing something wrong with a commit. But what
|
||||
if the commit is so far gone you'd rather just get rid of it and start over?
|
||||
This extra line in the description of ``lxqt-about-l10n`` isn't really useful,
|
||||
and it's probably not something that can be made useful in the future. This is
|
||||
where ``git reset`` comes in handy. Whereas ``git commit`` creates commits,
|
||||
``git reset`` destroys them. You can use ``git reset`` in a few different
|
||||
ways, the two most useful are:
|
||||
|
||||
* Mixed reset, which gets rid of commits but leaves the actual changes made in
|
||||
those commits in your working tree. Mixed reset is the default mode.
|
||||
* Hard reset, which gets rid of commits *and* resets all tracked files to
|
||||
a previous state. Note well that this resets *tracked* files. Files that are
|
||||
untracked will be left alone even by a hard reset. This is one of the ways
|
||||
Git treats tracked and untracked files differently.
|
||||
|
||||
To do a mixed reset to the previous commit, run::
|
||||
|
||||
git reset HEAD^
|
||||
|
||||
This will leave our changes intact, but the commit itself will be undone and
|
||||
the changes will *not* be staged for commit. You can now make more changes and
|
||||
then make a new commit, or you can completely undo all of our changes with::
|
||||
|
||||
git add -A
|
||||
git reset --hard HEAD
|
||||
|
||||
This will first stage all modifications, so that any untracked files are
|
||||
caught. Then it will hard-reset the repo back to the commit HEAD is pointing
|
||||
to, discarding our changes.
|
||||
|
||||
When you're doing work in a Git repo, it's generally a good idea to work on a
|
||||
branch other than the "primary" branch (``ubuntu/resolute`` in this instance).
|
||||
This makes it easier to avoid running into conflicts with other developers.
|
||||
It is possible to use ``git branch`` to create branches, but most of the time
|
||||
when you're making a branch, you also want to switch to the branch. For this,
|
||||
you can use the ``-b`` option of ``git checkout``, like so::
|
||||
|
||||
git checkout -b my-new-branch
|
||||
|
||||
Note that ``git checkout -b`` will fail if the branch already exists.
|
||||
|
||||
This is a good enough start for now. There are a few more things you'll want
|
||||
to know about Git in your work as a packager (namely rebasing, tagging,
|
||||
forking, and pushing), but it will be easiest to cover those as we need them.
|
||||
|
||||
Miscellaneous useful things to know about Git
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
* You can diff the contents of your working tree with the HEAD commit by using
|
||||
``git diff HEAD``. This is useful to see what all you've changed before
|
||||
committing it. Note that untracked files will be ignored when you do this.
|
||||
If you want to include those in the diff too, ``git add`` them first.
|
||||
* Raw diffs are oftentimes hard to read. If you want a more comfortable
|
||||
viewing experience, install Meld (``sudo apt install meld``), then use
|
||||
``git difftool --tool=meld --dir-diff`` instead of ``git diff``. This will
|
||||
let you visualize the changes between two commits in much more detail than a
|
||||
raw diff allows. You can even make (limited) changes to your working tree
|
||||
here by modifying files on the right side of the Meld window. (Be warned
|
||||
that changes made to the left side of the window will be silently discarded,
|
||||
and that copying files from the left side of the window to the right side
|
||||
will not work; those files will be silently discarded as well.)
|
||||
* You can checkout more than just branches. ``git checkout`` can be used on
|
||||
any ref. If you check out something other than a branch however, you will
|
||||
enter what Git calls "detached HEAD state". This means that any commits you
|
||||
make will not be integrated into any existing branch, and if you check
|
||||
something else out later, you'll probably have a hard time finding those
|
||||
commits later. If you decide you want to keep the changes you've made, use
|
||||
``git switch -c new-branch-name`` to make a new branch with any changes
|
||||
you've made so far.
|
||||
* As a general rule, do not use force-push unless you're fixing commits you
|
||||
just pushed. Other users may have pulled those commits, and will have to fix
|
||||
their repos if you do this. There are exception to this rule, you'll be able
|
||||
to spot them as you gain experience.
|
||||
|
||||
Foundations of Debian packaging
|
||||
-------------------------------
|
||||
|
||||
TODO
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user