git notes
What’s changed (Understanding diff)
(Q) How can I find the files that I’ve changed in this branch?
(A) I’ve setup an alias called git changed
git config --global alias.changed '!git diff --name-only $(git merge-base HEAD $(git symbolic-ref refs/remotes/origin/HEAD | sed "s@^refs/remotes/origin/@@"))'
This command does:
- Get’s the name of the branch your branch is off of (git symbolic-refs)
- Get’s the commit used when you created your branch (git merge-base)
- Runs the git command to list just the files that have changed (git diff –name-only $COMMIT_WHERE_BRANCH_WAS_CREATED)
(Q) How can I view all of the actual source code changes made to a file?
(A) Using git log -p
shows every commit that modified somefile and the actual source code changes made in that commit.
git log -p -- somefile
If you want to see the diff for ALL of the files in each commit that changed somefile then you can add
the --full-diff
option, like this:
git log -p --full-diff -- somefile
which will show diffs made in every commit that changed somefile.
This syntax -- somefile
filters/finds only commits where the file (path) specified was changed.
Git resolves somefile relative to the repository root (not necessarily your current directory). So a more realistic example might be
git log -p --full-diff -- src/main/java/com/example/play/hello.java
The src is relative to the root of the repostitory you are working on. If you specify a directory then
git will filter for any commit that changed ANY file within that directory (or sub-directories).
git log -p -- src/main/resources
So this will show a the difference to any file that was changed under src/main/resources
.
The -p
(patch) option causes the results diff results to be shown in patch format (aka diff format).
The diffs will include ALL files changed in that commit. The diffs shown will be for the commit being shown and the previous version of that file (aka the parent commit).
Diff Filters - find only commit where file was added or deleted
Filters commits to only show those where files were added (A) or deleted (D).
You can include multiple filters in one --diff-filter
option as shown.
git log --diff-filter=AD --name-only -- somefile
Common filters:
- A = Added
- C = Copied
- D = Deleted
- M = Modified
- R = Renamed
Changing the output of the diff
The git log command supports a --format
option which allows you to specify the format for log records.
For example,
git log --format="Commit: %h by %an on %ad"
# Sample output
Commit: abc123 by Alice on Mon Feb 19 12:00:00 2024
Commit: def456 by Bob on Sun Feb 18 15:30:00 2024
(Q) How can I get a single file from another branch?
(A) As follows
FILE=the/path/to/file.txt
git show TheBranch:$FILE > $FILE.tmp
diff $FILE.tmp $FILE
A practical example for using this was; Another developer committed to several repos that I’m working on updated the releases of those packages. I need to update my application to use the release versions that are now committed and in the master branch.
To do this, I wrote the following script:
# FILE: mygit-get-file
#!/bin/sh
LIMIT_LINES=9999999
STARTING_DIR=$(pwd)
for arg in $*
do
cd $STARTING_DIR
echo "FILE: $arg"
# Give relative filename from root of REPO/Some/Path/to/a/file.txt
# reponame=REPO
# dirname=Some/Path/to/a/file.txt
reponame=$(echo $arg | sed 's,/.*,,')
dirname=${arg#*/*}
cd $reponame
# Use main as the master branch if it exists, otherwise default to master for backwards historical reasons
if [ "`git branch -r | grep main`" != "" ]
then
MAIN_BRANCH_NAME=main
else
MAIN_BRANCH_NAME=master
fi
echo "cd $reponame; git fetch; git show origin/$MAIN_BRANCH_NAME:$dirname | head -$LIMIT_LINES)"
git fetch; git show origin/$MAIN_BRANCH_NAME:$dirname | head -$LIMIT_LINES
echo "------------------------------------------------------------"
done
How can I see the file somefile
git show next~10:Documentation/README
Shows the contents of the file Documentation/README as they where in the 10th to the last commit on the branch next. See https://git-scm.com/docs/git-show.
Deleting branch, tag, commit
(Q) How can I delete a tag both locally and remotely?
(A) As follows
git tag -d 1.6.3
git push --delete origin 1.6.3
(Q) How can I delete a branch both locally and remotely?
(A) A similar syntax is used to delete a local/remote branch, but branches might have issues deleting.
# git tag tbd/branch1 # Optionally tag a branch if you might need to get back to it
git branch -d feature/branch1
git push --delete origin feature/branch1
Git will only delete the branch if it has already been fully merged into the current branch (or another specified branch).
NOTE: If the -d
option doesn’t work because the branch is currently being merged or for some other reason you can
use the -D
option to force the deletion of the branch.
NOTE2: To get back to a branch that you deleted, you can use
git checkout -b feature/branch1 tbd/branch1
Branch Hygiene
Periodically, you’ll want or need to cleanup/delete your local branches (Q) How can I get the pom version out of a pom.xml file to use it when creating a git tag for a release? (A) MVN_VER=$(mvn help:evaluate -Dexpression=project.version -q -DforceStdout)
Git tags
Git has two kinds of tags. Annotated an unannotated. To see which is which run the command
git for-each-ref refs/tags --format="%(refname:short) -> %(objecttype) (%(*objectype)) %(objectname:short) %(authordate:iso8601-strict) %(*authorname)"
25.1 -> tag (commit)
tags/jira-123-wip -> commit
# Things you can do with tags
git show jira-123-wip
git co jira-123-wip
# Then you can
git cat-file -t 25.1
So what’s the difference?
- An annotated tag is a GIT object, so questions about a tag, you can ask about the GIT OBJECT or the object that the tag
points to.
- In the
--format
argument when you see a star (authorname), the star means what the object points to so this only happens for *annotated objects.
- In the
- A unannotated tag is simply an alias for a hash aka a commit. Also called a reference.
What is quite confusing about git tags is how some git command work off of git objects and others work off of the pointers.
An anaology (that is not perfect) is a symbolic link in UNIX. When you issue the ls
(list files) commands for
a directory that contains the symbolic link do you want to see the metadata about the symbolic link or the metadata (e.g., file creation date)
of the file the symbolic link points to. Well, in most cases you want to operate on the file the symbolic link points to
and that is how many git commands work. So in most cases you can treat a tag as a hash because that’s how it’s most often used.
To create an annotated hash you can do
git tag -a v1.0.0 -m "Release version 1.0.0"
RefLogs
You can think of reflogs as a log of every transaction that GIT does. Conceptually, it can be thought of as Git’s “undo history”.
Reflogs are local only and expire (usually after 90 days). You can configure this:
git config --global gc.reflogExpire "30 days"