Recording Changes – Revisited#
Learning objectives#
Understand how to incrementally stage changes in a file using Git
Learn to stage multiple files at once in a Git repository
Comprehend how to delete and move files under version control within a Git repository
Familiarize with the commands
git rm
andgit mv
for managing files in GitPractice making commits with staged changes and viewing the log of recent commits
Staging in steps#
The last exercise in the previous episode, Viewing History and Changes, began to touch on an important point about staging changes to files. It is possible to stage some changes to a file, then make further changes to the same file.
For example, suppose we want to start adding content to Git-cheatsheet.md
about git diff
:
## Viewing changes
`git diff <files>` — Show changes to files that have not yet been staged.
`git diff <commit1> <commit2> <files>` — Show the differences in files between
two commits.
Let’s stage these changes:
$ git add Git-cheatsheet.md
Now let’s add some content about the --name-only
optional argument for
git diff
to the cheatsheet:
`git diff --name-only ...` — Only show the names of files that have changed.
Now run git status
:
$ git status
On branch main
Your branch is ahead of 'origin/main' by 6 commits.
(use "git push" to publish your local commits)
Changes to be committed:
(use "git restore --staged <file>..." to unstage)
modified: Git-cheatsheet.md
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: Git-cheatsheet.md
Git-cheatsheet.md
appears as a file that has both changes to be staged and
also further changes that have not yet been staged, which makes sense. From
here, we could
commit the staged changes (i.e. the content about
git diff <files>
andgit diff <commit1> <commit2> <files>
), leaving the material aboutgit diff --name-only ...
as ‘work in progress’ in the working tree; orstage the further changes about
git diff --name-only ...
, so that they join what’s already been staged; orleave things as they are and continue working on files in the repository.
This gives us a lot of flexibility to make our commits nice and tidy. Let’s go for the first option. We make the commit and then view the remaining changes left in the working tree:
$ git commit -m "Add entries about 'git diff' to cheatsheet"
[main 9bb2714] Add entries about 'git diff' to cheatsheet
1 file changed, 8 insertions(+)
$ git diff
diff --git a/Git-cheatsheet.md b/Git-cheatsheet.md
index 75e4430..acff2ee 100644
--- a/Git-cheatsheet.md
+++ b/Git-cheatsheet.md
@@ -34,3 +34,5 @@
`git diff <commit1> <commit2> <files>` — Show the differences in files between
two commits.
+
+`git diff --name-only ...` — Only show the names of files that have changed.
As expected, the changes left to stage are about the --name-only
option. Let’s
tidy up by doing a round of ‘add-commit’ on these changes, then viewing the log
to see our last two commits:
$ git add Git-cheatsheet.md
$ git commit -m "Add note about '--name-only' option to 'git diff'"
[main 910bb79] Add note about '--name-only' option to 'git diff'
1 file changed, 2 insertions(+)
$ git log -2 --oneline
910bb79 (HEAD -> main) Add note about '--name-only' option to 'git diff'
9bb2714 Add entries about 'git diff' to cheatsheet
Staging multiple files#
It can be a bit tedious to list out each file whose changes need to be staged,
or who’s diffs we want to examine. Git provides convenient shorthands to refer
to multiple files at once. For example, if path/to/directory
defines a
directory within the root folder of our repository, the command
git add path/to/directory
would stage all changes to files that are contained in path/to/directory
or in
directories descended from it. (So, for example, both the files
path/to/directory/file1.txt
and path/to/directory/foo/bar/file2.txt
would
be included by the above command.) A particular example is the case where
path/to/directory
is just the current working directory, i.e. .
. If our
current working directory is the root directory of the repository, then the
command
git add .
would stage changes to all files contained in the repository root directory or any directory descended from it. This can be a useful to way to grab all changes to all files in a repository.
Caution with
git add .
Exercise caution when running
git add .
, because you may end up staging changes to files you didn’t intend to!
The above examples work analogously with git diff
as well.
Pathspecs
The shorthands introduced here are examples of what are called pathspecs. This is Git’s terminology for referring to files, in a way that provides more flexibility than just listing out all file paths individually. If you look at the Git help pages for commands like
git add
andgit diff
, you may well find that the command signature includes mention of<pathspec>
rather than ‘files’. You can think of this<pathspec>
entry as meaning ‘file paths, or shortcut syntax for specifying multiple files in one go’. We’ll see a bit more about this later in the course. If you want to read more, check out the Git Glossary manual by runningman gitglossary
and paging down to thepathspec
entry.
Deleting and moving files#
Sometimes we may need to delete, move or rename files that are under version control
in a repository (i.e. that feature in commits in the repository). Git has
specific commands to do this: git rm
for deletion
and git mv
for moving and renaming. The key things to remember about these
commands are:
they only work when applied to files under version control; and
they perform the deletion / move and then stage the result, ready for committing.
Comparison with
rm
andmv
You may be familiar with the Unix commands
rm
(for deleting files) andmv
(for moving files). If you use these commands on files that are under version control, then the changes will be detected by Git but not staged. Thegit rm
andgit mv
versions automatically perform the staging for you. If a file is not under version control, then you should use the usual Unix commands for deletion and moving.
Deletion#
The general form for deleting files that is under version control is
git rm <files>
Let’s create a new file, rubbish.txt
that we’ll put in the root folder
of the git-good-practice
repository. For the purposes of demonstration, we’ll
commit this file and then delete it. First, we create a commit for the file:
$ git add rubbish.txt
$ git commit -m "Add some rubbish to try out 'git rm'"
[main d26a698] Add some rubbish to try out 'git rm'
1 file changed, 0 insertions(+), 0 deletions(-)
create mode 100644 rubbish.txt
Now we apply git rm
on the rubbish.txt
file and check the status after having
done so:
$ git rm rubbish.txt
rm 'rubbish.txt'
$ git status
On branch main
Your branch is ahead of 'origin/main' by 9 commits.
(use "git push" to publish your local commits)
Changes to be committed:
(use "git restore --staged <file>..." to unstage)
deleted: rubbish.txt
The deletion has been staged, but not yet committed to the repository. Moreover,
if we view the contents of the folder with ls
, we can see the file has been
deleted from the file system:
$ ls
Commit-good-practice.md Git-cheatsheet.md README.md
We then commit the deletion to the repository in the usual way:
$ git commit -m "Remove rubbish.txt"
[main 5cf8321] Remove rubbish.txt
1 file changed, 0 insertions(+), 0 deletions(-)
delete mode 100644 rubbish.txt
Moving#
The general form of the git mv
command is:
git mv <source-file> <destination>
Note that if <destination>
is a directory, the file will be
moved there but keep the same name; otherwise, the file will be renamed to
<destination>
. Note that the directories in the destination path must already
exist. Here are some examples:
If
foo/bar
is an existing directory path from the current working directory, thengit mv file.txt foo/bar/baz.txt
will move the filefile.txt
to the new file./foo/bar/baz.txt
(and stage this move).If
foo
is a directory, thengit mv file.txt foo
will movefile.txt
to./foo/file.txt
git mv file.txt newfile.txt
will renamefile.txt
tonewfile.txt
.
Exercise
We may want to create more ‘good practice’ files as we go through this course, so let’s prepare by moving
Commit-good-practice.md
to a directory calledGood-practice-guides
in the root folder of the repository. Make this directory and then create a commit that movesCommit-good-practice.md
to this directory.