Here goes more advanced Git commands not found among the basic ones.
for-each-ref
Display info in .git/refs
.
#!/bin/sh
git for-each-ref --shell --format="ref=%(refname)" refs/tags | \
while read entry
do
eval "$entry"
echo `dirname $ref`
done
This modified example taken from the one in the official manual pipes
ref=refs/tags/181116
ref=refs/tags/copyBtn0
ref=refs/tags/fa531
ref=refs/tags/solarized
to a while
loop. In each iteration, the read
command reads each line in the
piped output and sets it into the variable entry
. The command will exit
normally unless it meets an EOF, so that the code inside can be executed. The
variable eval
set the shell variable ref
to the output Git reference name.
dirname
chops off the tag names (181116
, fa531
, etc) and returns
refs/tags
.
Using refname:short
will give short reference names that we usually type in
the terminal. The wildcard *
has to be escaped by an antislash \
in the
last argument.
To remove remote branches (both local and remote copies), xargs
won’t work because it’s impossible to deal with the white space following
the colon in the command ... | xargs git push origin :
. A while
loop has to
be used to loop through all matching refname
s.
The following command deletes all remote branches whose name begins with
staticman
in both the remote Git server and the local repo.
git for-each-ref --shell --format="%(refname:short)" refs/remotes/origin/staticman\* | \
grep -o 'staticman_[a-z0-9-]*' | while IFS="" read -r branch; do
git push origin :$branch
done
ls-files, ls-tree
List files (resp. files in tree). ls-tree
displays a table with permissions,
Git object types, full SHA1 hashes and file names.
Examples
$ git ls-files
.gitignore
.gitlab-ci.yml
.gitmodules
LICENSE
archetypes/default.md
...
static/js/katex-macros.js
staticman.yml
themes/beautifulhugo
$ git ls-tree origin/master:content/page
100644 blob 1604fbe12feb561b557eab2e7fa5ec95bc68a649 about.md
040000 tree 599c4da34630b2068121a66cf3e82e3e560e3590 advanced-git
040000 tree 10ec0300326e712dc468e4a47826f6056c5eb4a4 bash-commands
100644 blob bd6da925f4118b83fc42eb9af4c33efe53b7ab2c math-se-comment-templates.md
040000 tree 6a196a2c445425ab4e05940dc84257ad002516fa sublime
$ git ls-tree -r origin/master:content/page
100644 blob 1604fbe12feb561b557eab2e7fa5ec95bc68a649 about.md
100644 blob 5dccbc2c2dfee0bb50809292019af599aee01e4b advanced-git/index.md
100644 blob ef7356ed7a22d0acc1fc4bfcf089828852b1b890 bash-commands/180826153752-xubu1804-w400.png
100644 blob d85403db306fde697fd18c19723ca9aa54bd9496 bash-commands/180826153752-xubu1804.png
100644 blob dd65a9113abd99da6586dfb176cda5c2a88392ba bash-commands/index.md
100644 blob bd6da925f4118b83fc42eb9af4c33efe53b7ab2c math-se-comment-templates.md
100644 blob 472b544e4497be91d40af7aa937ca8c7f1f9ac53 sublime/index.md
Options for ls-tree
:
-r
: recursive--names-only
: print only the file names
Applications
For iteration over cached files only if the file name is “regular enough”. These two commands are synonymous to each other.
Missing EOF detection
Crude version:
!# /bin/sh
g ls-files 1_chapter | \
while IFS= read -r file; do
echo $file
tail -c1 $file | od -c
test `tail -c1 $file` && echo 'missing EOF!' || echo 'has EOF'
done
The output on this GitHub repo would look like
1_chapter/bubbleSort.jl
0000000 )
0000001
missing EOF!
1_chapter/comprehension.jl
0000000 \n
0000001
has EOF
See test
for an explanation for what test
does.
merge-base
Return the SHA1 hash of the youngest common ancestor of two branches.
$ git merge-base master dev
merge –squash, rebase -i
merge --squash <src>
condenses commits into one on the current branch
without touching src
.
rebase
, meaning “re-base”, is analogous to a pot transplant. The -i
flag
opens an interactive session for that. The text editor opened is determined by
the parameter core.editor
.
Applications
Both merge --squash
and rebase
can be used for cleaning the commit history.
The former can be used if <src>
branch is to be thrown away. In rebase -i
,
one can also squash Git commits.
reflog
Track the SHA1 hash that HEAD
represents.
Applications
Find lost commit.
rev-parse
Return the SHA1 hash that Git ref
represents.
$ rev-parse FETCH_HEAD # head of fetched commits
Applications
Verify repo status.
diff
Some advanced options that enable us to spot out differences invisible using normal commands.
--ws-error-highlight=<kind>
: highlight whitespace errors at lines of type<kind>
ingit diff
’s output.<kind>
is a comma-separated list ofnew
(+
),old
(-
) andcontext
(neither+
nor-
) lines.all
is a shorthand forold,new,context
.--ignore-all-space
--ignore-blank-lines
--ignore-space-at-eol
--ignore-space-change
--ignore-submodules
fsck
Run a file system check. I use this for retrieving --unreachable
commits.
The --no-reflogs
overturns the default behavior of treating commits in the
reflog
as reachable.
The output has three columns.
$ git fsck --full --unreachable --no-reflogs
Checking object directories: 100% (256/256), done.
Checking objects: 100% (502/502), done.
unreachable tree 1e004e2884574d5a17b290632e4fb55e3feae750
unreachable blob 5300d869180014538a6081418a0e6984c0c4130d
unreachable tree 7720282acf3279de0508633055082a7bd893d732
...
We can
- apply a filter on 2nd column to get
commit
type - map the third column to a meaningful one line summary
- sort by reversed chronological order
- list only the first
N
entries.
$ git fsck --full --unreachable --no-reflogs | \
awk '/commit/ {
system("git -P show --no-patch --format=format:\"%h <%an> %as %s%n\" " $NF)
}' | sort -rk3 | head -n3
Checking object directories: 100% (256/256), done.
Checking objects: 100% (502/502), done.
33c5ee5 <Vincent Tam> 2021-08-23 Fixed two recent posts' heading level
61f9eea <Vincent Tam> 2019-05-10 Bash & Git: added section
b771614 <Vincent Tam> 2019-05-09 Pages: Git & Bash