History: log -p, show, blame
The /etc/demo repository with three commits by two authors:
student@node1:/etc/demo$ sudo git log --format='%h %an %ad %s' \
> --date=short
c9ab4a3 Boris Ops 2026-10-09 site: tune listen
4c69b7d Boris Ops 2026-10-05 site: move root to /srv/www
f7de9e0 Anna Admin 2026-10-01 site: initial config
git log -p adds each commit's change; with -1 only the last one,
with -- <file> only the commits touching that file:
student@node1:/etc/demo$ sudo git log -p -1 -- site.conf
commit c9ab4a3032a1cf6f1f4b1fee565958cfaf2f67c4
Author: Boris Ops <boris@lab.local>
Date: Fri Oct 9 09:15:00 2026 +0000
site: tune listen
diff --git a/site.conf b/site.conf
index d988f4e..f671dff 100644
--- a/site.conf
+++ b/site.conf
@@ -1,4 +1,4 @@
server {
- listen 80;
+ listen 8O;
root /srv/www;
}
- is the line before the commit, + after it: 80 became 8O with
the letter O. git show <commit> prints one commit the same way, with
--stat only the list of files. git blame labels each line of a file
with the commit that last changed it:
student@node1:/etc/demo$ sudo git blame site.conf
^f7de9e0 (Anna Admin 2026-10-01 10:00:00 +0000 1) server {
c9ab4a30 (Boris Ops 2026-10-09 09:15:00 +0000 2) listen 8O;
4c69b7d7 (Boris Ops 2026-10-05 14:30:00 +0000 3) root /srv/www;
^f7de9e0 (Anna Admin 2026-10-01 10:00:00 +0000 4) }
A ^ before the hash marks the repository's first commit. An
uncommitted change shows in git status (modified: site.conf) and
git diff.
Undo a change and a commit: restore, revert, reset
| What to undo |
Command |
History |
| an uncommitted change to a file |
git restore site.conf |
unchanged |
| one commit |
git revert --no-edit <commit> |
a new commit on top |
| a file, back to an old commit's version |
git restore --source=<commit> site.conf |
unchanged, the change is in the working file |
| the branch, back to an old commit |
git reset --hard <commit> |
the commits after it leave the branch |
revert makes a commit that is the reverse of the chosen one — the
history stays, and it shows who undid what and when:
student@node1:/etc/demo$ sudo git revert --no-edit HEAD
[main 107f37c] Revert "site: tune listen"
Date: Wed Oct 21 11:54:18 2026 +0000
1 file changed, 1 insertion(+), 1 deletion(-)
The message of such a commit says This reverts commit c9ab4a30…. You
can undo an old commit too (git revert --no-edit HEAD~2): git removes
only its change and keeps the later ones. To look at a file from an old
commit without changing anything — git show HEAD~3:site.conf.
reset --hard rewrites the branch: the commits after the chosen one
leave it, and uncommitted changes are gone for good. git reflog
remembers the commits that left:
student@node1:/etc/demo$ sudo git reflog | head -3
107f37c HEAD@{0}: reset: moving to HEAD~1
d01f2cc HEAD@{1}: revert: Revert "site: move root to /srv/www"
107f37c HEAD@{2}: revert: Revert "site: tune listen"
git reset --hard 'HEAD@{1}' takes the branch back to where it was
before the reset. In a shared repository that others pull from,
history is not rewritten — there you undo with revert.
A root-owned repository: sudo git
Files in /etc belong to root, and so does a repository in
/etc/nginx. git commands there go through sudo, like editing the
config. sudo git takes the author name and email from root's settings
— your git config --global is not visible to it. So set them in the
repository itself:
sudo git -C /etc/nginx config user.name 'Lab Admin'
sudo git -C /etc/nginx config user.email 'admin@lab.local'
Without this sudo git commit and sudo git revert answer
Author identity unknown — git. git without sudo in
someone else's repository refuses to work — git.
A remote repository: fetch, pull, push
A bare repository is history only, with no
working files: commits are pushed to it from different machines. A
working copy on a server is a clone, and its remote is called origin:
git init --bare -b main /srv/git/site.git
git clone /srv/git/site.git ~/site
git remote -v
git status compares the branch with what git knew about origin at
the last exchange. It sees a colleague's new commit after git fetch:
student@node1:~/w1$ git fetch
From /srv/git/site
b1ad7d1..8396b40 main -> origin/main
student@node1:~/w1$ git status | head -2
On branch main
Your branch is behind 'origin/main' by 1 commit, and can be
fast-forwarded.
git log --oneline HEAD..origin/main shows which commits will come,
git diff HEAD origin/main what they will change. git pull is fetch
plus a merge; if you have no commits of your own, the branch simply
moves forward (Fast-forward).
git push sends your commits. If origin has commits you do not have,
push refuses:
! [rejected] main -> main (fetch first)
error: failed to push some refs to '/srv/git/site.git'
git pull first, then git push again. If both you and origin have
new commits, the branches have diverged, and git pull asks how to
reconcile them — git.
git stash moves uncommitted changes to a separate store and brings the
files back to the last commit — so you can get other people's commits
when pull refuses because of a local change:
student@node1:~/w1$ git stash
Saved working directory and index state WIP on main: b1ad7d1 site: v1
student@node1:~/w1$ git pull
Updating b1ad7d1..8396b40
Fast-forward
index.html | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
student@node1:~/w1$ git stash pop
Auto-merging index.html
CONFLICT (content): Merge conflict in index.html
...
The stash entry is kept in case you need it again.
git stash list shows what is shelved (stash@{0}: WIP on main: …),
git stash pop brings the change back and removes it from the store.
Here the returned change touched the same line that came with pull —
a conflict (git), and the entry stayed in the store. Remove
it after resolving — git stash drop.
A conflict means both sides changed the same
lines, and git does not know which version to keep. It writes both into
the file:
<<<<<<< Updated upstream
v2 colleague
=======
v1 local edit
>>>>>>> Stashed changes
Between <<<<<<< and ======= is the version already in the branch,
between ======= and >>>>>>> the one coming in. After stash pop the
markers say Updated upstream and Stashed changes, after pull —
HEAD and the commit hash. git status shows such files as
both modified.
To resolve:
- Open the file, keep what is needed, remove all three markers.
git add <file> — the conflict is resolved.
- After
pull — git commit (the merge message is ready); after
stash pop no commit is needed, the change is simply back in the
working files.
Changed your mind about merging — git merge --abort: the files go back
to how they were before pull.