Posts tagged: git

All posts with the tag "git"

25 posts latest post 2026-05-06
Publishing rhythm
May 2026 | 1 posts

I just learned that forgejo has a push to create repo feature and it is a gamechanger. Upon first try it didn’t work, with just a couple of environment variables I was up and running with push to create.

notify.wayl.one on  main is 📦 v0.1.62  v3.14.4  NO PYTHON VENV SET  USING SYSTEM NVIM
❯ git remote add origin https://git.waylonwalker.com/waylon/notify.wayl.one
notify.wayl.one on  main is 📦 v0.1.62  v3.14.4  NO PYTHON VENV SET  USING SYSTEM NVIM
❯ git push
remote: Push to create is not enabled for users.
fatal: unable to access 'https://git.waylonwalker.com/waylon/notify.wayl.one/': The requested URL returned error: 403

So I added the following environment variables.

Author: Waylon S. Walker <[email protected]>
Date:   Wed May 6 21:56:53 2026 -0500

    enable push to create

diff --git a/k8s/forgejo/deployment.yaml b/k8s/forgejo/deployment.yaml
index d77daab..9346763 100644
--- a/k8s/forgejo/deployment.yaml
+++ b/k8s/forgejo/deployment.yaml
@@ -91,6 +91,10 @@ spec:
               value: "0.0.0.0"
             - name: FORGEJO__server__HTTP_PORT
               value: "3000"
+            - name: FORGEJO__repository__ENABLE_PUSH_CREATE_USER
+              value: "true"
+            - name: FORGEJO__repository__ENABLE_PUSH_CREATE_ORG
+              value: "true"
             - name: FORGEJO__database__DB_TYPE
               value: postgres
             - name: FORGEJO__database__HOST

https://github.com/WaylonWalker/homelab-argo/commit/b2e953bc12

Tried again, and it just worked!

notify.wayl.one on  main is 📦 v0.1.62  v3.14.4  NO PYTHON VENV SET  USING SYSTEM NVIM
❯ git push
Enumerating objects: 171, done.
Counting objects: 100% (171/171), done.
Delta compression using up to 12 threads
Compressing objects: 100% (169/169), done.
Writing objects: 100% (171/171), 176.22 KiB | 16.02 MiB/s, done.
Total 171 (delta 99), reused 0 (delta 0), pack-reused 0 (from 0)
remote: Resolving deltas: 100% (99/99), done.
To https://git.waylonwalker.com/waylon/notify.wayl.one
 * [new branch]      main -> main

📝 Git Notes

See old revisions of one file # [1] git log --oneline -- <file> git log -n 2 --oneline -- <file> Checkout an old revision of a file # [2] git checkout <commit> -- path/to/file fuzzy pick a file and check out an old revision # [3] #!/usr/bin/env bash set -euo pipefail file="${1:-}" if [[ -z "${file}" ]]; then file="$(git ls-files | fzf --prompt="select file > ")" || exit 0 fi if [[ -z "${file}" ]]; then exit 0 fi if ! git rev-parse --is-inside-work-tree >/dev/null 2>&1; then echo "Not a git repository." >&2 exit 1 fi if ! git ls-files --error-unmatch -- "${file}" >/dev/null 2>&1; then echo "File is not tracked by git: ${file}" >&2 exit 1 fi choice="$( git log --follow --pretty=format:'%h %ad %s' --date=short -- "${file}" | fzf --ansi --no-sort --reverse \ --preview-window=down:70% \ --prompt="checkout revision > " \ --preview "git show --color=always {1}^..{1} -- '${file}' 2>/dev/null || git show --color=always {1} -- '${file}'" )" if [[ -z "${choice}" ]]; then ...
1 min read

--name-status is a great way to see what files have changed in a git diff alongside the status code. I recently used this in a script to create a report of new and modified files during a build.

git diff --name-status
git diff --name-status origin/main
git diff --name-status --staged
git diff --name-status 'HEAD@{3 days ago}'

The tea command for gitea (used by forgejo) has a flag for login. With gitea you can have multiple accounts logged in. When you try to run a command such as repo create it will prompt you which login to use, but I learned that you can bake it in to all of them with --login <login-name>

❯ tea repo create --name deleteme --description 'for example'
┃ NOTE: no gitea login detected, whether falling back to login 'git.waylonwalker.com'?
image showing message NOTE: no gitea login detected, whether falling back to login ‘git.waylonwalker.com’?
tea repo create --name deleteme --description 'for example' --login git.wayl.one
You already have a git server: (Maurycy's blog) maurycyz.com [1] It’s so easy to forget low level tech sometimes. Things that are dead simple and just work without a hitch. git is one of those rock solid things thats very easy to remember all that it does, this is a classic use case. This just works cd /parent/directory/for/repo git clone ssh://username@server/path/to/repo In order to recieve you must update the remote to allow recieve. git config receive.denyCurrentBranch updateInstead Now you can pull update push. It’s funny how this was the way I first learned to do Continuous Deployment to a RHEL7 machine, also how Heroku worked, but its so easy to forget this solution is there. I come across it every few years and immediately have a few use cases in mind. References: [1]: https://maurycyz.com/misc/easy_git/
Learn to use email with git! git-send-email.io [1] This site gives us a glimpse into the development workflow using git [2] over email, without remote centralized servers. I found it interesting how patches can be sent with an optional cover letter nearly like a pr would be made. References: [1]: https://git-send-email.io/ [2]: /glossary/git/
Repository Mirrors | Forgejo – Beyond coding. We forge. forgejo.org [1] Forgejo supports repository mirrors, I think this is how I am going to handle migrating all of my github repos into forgejo. over time I’ll probably go through and delete a bunch of unnecessary one from github, ones that might have a user or two I might keep on github. I have such small scale projects with almost no users I am not sure that It really matters for me or not. References: [1]: https://forgejo.org/docs/latest/user/repo-mirror/
Let's Make Sure Github Doesn't Become the only Option - Edward Loveall blog.edwardloveall.com [1] This post is a masterclass in blogging, cross linking, backing up your ideas with posts from other great sources. I have a week of reading inside this post, and need to come back later when Im not sick. References: [1]: https://blog.edwardloveall.com/lets-make-sure-github-doesnt-become-the-only-option
- Damn Prime covers this so well from all angles. Can’t overstate the importance of that last step. Look at the issues, and raise an issue if there is not one before putting in a bunch of hard work. Make sure that the maintainers are open for your changes and no one else is already working on it. References: [1]: /glossary/git/
Some Git poll results Some Git poll results Julia Evans · jvns.ca [1] great poll of git [2] questions poll: did you know that in a git merge conflict, the order of the code is different when you do a merge/rebase? merge: <<<<<<< HEAD YOUR CODE OTHER BRANCH’S CODE c694cf8aabe rebase: «««< HEAD OTHER BRANCH’S CODE YOUR CODE d945752 (your commit message) This one explains a lot. I think I knew this, I might have seen it somewhere, but I have definitely noticed it go both ways and confuse the crap out of me. Feels very similar to how --ours and --theirs flip flops. References: [1]: https://jvns.ca/blog/2024/03/28/git-poll-results/ [2]: /glossary/git/
Astronaut doing a mic drop with explosion

Recently I added two new bash/zsh aliases to make my git experience just a tad better.

trackme #

Most of our work repos were recently migrated to new remote urls, we scriped out the update to all of the repos, but I was left with a tracking error for all of my open branches. To easily resolve this I just made an alias so that I can just run trackme anytime I see this error.

There is no tracking information for the current branch.
    Please specify which branch you want to merge with.
    See git-pull(1) for details

    git pull <remote> <branch>

If you wish to set tracking information for this branch you can do so with:

    git branch --set-upstream develop origin/<branch>

getting the branch #

The following command will always return the currently checked out branch name.

git symbolic-ref --short HEAD

Injecting this into the suggested git command as a subshell gives us this alias that when ran with trackme will automatically fix tracking for my branch.

alias trackme='git branch --set-upstream-to=origin/$(git symbolic-ref --short HEAD)'

rebasemain #

I sometimes get a bit lazy at checking main for changes before submitting any prs, so again I made a quick shell alias that will rebase main into my branch before I open a pr.

alias rebasemain='git pull origin main --rebase'

The Aliases #

Here are both of the alias’s, feel free to steal and modify them into your dotfiles. If you are uniniatiated a common starting place to put these is either in your ~/.bashrch or ~/.zshrc depending on your shell of choice.

alias trackme='git branch --set-upstream-to=origin/$(git symbolic-ref --short HEAD)'
alias rebasemain='git pull origin main --rebase'

I love getting faster in my workflow, something I have recently added in is creating GitHub repos with the cli. I often create little examples of projects, but they just end up on my machine and not anywhere that someone else can see, mostly because it takes more effort to go create a repo. TIL you can create a repo right from the command line and push to it immediately.

gh repo create waylonwalker-cli
gh-repo-create.webp

want to see what this repo I created is about? #

Check out what I created here.

pipx run waylonwalker

Sometimes you have a pretty old branch you are trying to merge into and you are absolutely sure what you have is what you want, and therefore you don’t want to deal with any sort of merge conflicts, you would rather just tell git to use my version and move on.

update main #

The first step is to make sure your local copy of the branch you are moving into is up to date.

git checkout main
git pull

update your feature branch #

It’s also worth updating your feature branch before doing the merge. Maybe you have teammates that have updated the repo, or you popped in a quick change from the web ui. It’s simple and worth checking.

git checkout my-feature
git pull

start the merge #

Merge the changes from main into my-feature branch.

git merge main

Now is where the merge conflict may have started. If you are completely sure that your copy is correct you can --ours, if you are completely sure that main is correct, you can --theirs.

git checkout --ours .
git merge --continue

This will pop open your configured git.core.editor or $EDTIOR. If you have not configured your editor, it will default to vim. Close vim with <escape>:x, accepting the merge message.

Now push your changes that do not clash with main and finish your pr.

git push

I am getting ready to do some timeseries analysis on a git repo with python, my first step is to figure out a way to list all of the git commits so that I can analyze each one however I want. The GitPython library made this almost trivial once I realized how.

from git import Repo

repo = Repo('.')
commits = repo.iter_commits()

This returns a generator, if you are iterating over them this is likely what you want.

commits
# <generator object Commit._iter_from_process_or_stream at 0x7f3307584510>

The generator will return git.Commit objects with lots of information about each commit such as hexsha, author, commited_datetime, gpgsig, and message.

next(commits)
# <git.Commit "d125317892d0fab10a36638a2d23356ba25c5621">

I was editing some blog posts over ssh, when I ran into this error. gpg was failing to sign my commits. I realized that this was because I could not answer to the desktop keyring over ssh, but had no idea how to fix it.

Error #

This is the error message I was seeing.

gpg failed to sign the data ssh

The fix #

The fix ended up being pretty simple, but quite a ways down this stack overflow post. This environment variable tells gpg that we are not logged into a desktop and it does not try to use the desktop keyring, and asks to unlog the gpgkey right in the terminal.

export GPG_TTY=$(tty)

The log in menu #

This is what it looks like when it asks for the passphrase.

enter your passphrase to unlock your gpg key

EDIT-another way #

So this did not fix the issue on Arch BTW, and I have seen it not work for wsl users either. This did work for me and reported to have worked by a wsl user on a github issue.

echo '' | gpg --clearsign

This will unlock the gpg key then let you commit.

Sometimes you get a PR on a project, but cannot review it without wrecking your current working setup. This might be because it needs to be compiled, or a new set of requirements. Git worktrees is a great way to chekout the remote branch in a completely separate directory to avoid changing any files in your current project.

# pattern
# git worktree add -b <branch-name> <PATH> <remote>/<branch-name>
git worktree add -b fix-aws-service-cnsn /tmp/project origin/fix-aws-service-cnsn

This will create a new directory /tmp/project that you can review the branch fix-aws-service-cnsn from the remote origin. If you have setup different remotes locally you can check for the name of it with git remote -v

GitPython is a python api for your git repos, it can be quite handy when you need to work with git from python.

Use Case #

I recently made myself a handy tool for making screenshots in python and it need to do a git commit and push from within the script. For this I reached for GitPython.

How I Quickly Capture Screenshots directly into My Blog

Installation #

GitPython is a python library hosted on pypi that we will want to install into our virtual environments using pip.

pip install GitPython

Create a Repo Object #

Import Repo from the git library and create an instance of the Repo object by giving it a path to the directory containing your .git directory.

from git import Repo
repo = Repo('~/git/waylonwalker.com/')

Two interfaces #

from the docs

It provides abstractions of git objects for easy access of repository data, and additionally allows you to access the git repository more directly using either a pure python implementation, or the faster, but more resource intensive git command implementation.

I only needed to use the more intensive but familar to me git command implementation to get me project off the ground. There is a good tutorial to get you started with their pure python implementation in their docs.

Status #

Requesting the git status can be done as follows.

note I have prefixed my commands with »> to distinguish between the command I entered and the output.

>>> print(repo.git.status())

On branch main
Your branch is ahead of 'origin/main' by 1 commit.
  (use "git push" to publish your local commits)

Untracked files:
  (use "git add <file>..." to include in what will be committed)
        blog/

You can even pass in flags that you would pass into the cli.

>>> print(repo.git.status("-s"))

<!--markata-attribution-->
?? blog/

log #

Example of using the log.

print(repo.git.log('--oneline', '--graph'))

* 0d28bd8 fix broken image link
* 3573928 wip screenshot-to-blog
* fed9abc wip screenshot-to-blog
* d383780 update for wsl2
* ad72b14 wip screenshot-to-blog
* 144c2f3 gratitude-180

Find Deleted Files #

We can even do things like find all files that have been deleted and the hash they were deleted.

print(repo.git.log('--diff-filter', 'D', '--name-only', '--pretty=format:"%h"'))

git find deleted files

full post on finding deleted files

My Experience #

This library seemed pretty straightforward and predicatable once I realized there were two main implementations and that I would already be familar with the more intensive git command implementation.

Setting up your git pager to your liking can help you navigate diffs and logs much more efficiently. You can set it to whatever pager you like so that your keys feel nice and smooth and your fingers know exactly what to do. You might even gain a few extra features.

Setting the pager #

You can set the pager right from your command line with the following command.

git config --global core.pager 'more'

You can also set your pager by editing your global .gitconfig file which by default is set to ~/.gitconfig.

[core]
    pager = more

Color #

In my experience you need to turn colors off with nvim. bat handles them and looks good either way, but nvim will be plain white and display the color codes as plain text if color is on.

git config --global color.pager no

Pagers I have tried #

Here are some various configs that I tried. For some reason line numbers in bat really bothered me, but when in nvim they felt ok. I am going to try running both of them for a few days and see which I like better. I think having some of my nvim config could be really handy for things like yanking a commit hash to the system clipboard without touching the mouse.

# bat
git config --global core.pager 'bat'

# nvim in read only mode
git config --global core.pager 'nvim -R'

# turn colors off
git config --global color.pager no

# bat with no line numbers
git config --global core.pager 'bat --style=plain'

# nvim with no line numbers and a specific rc file
git config --global core.pager "nvim -R +'set nonumber norelativenumber' -u ~/.config/nvim/init-git.vim"

reset back to the default #

If you are afraid to try one of these settings, don’t be you can always change it back. If you tried one and dont like it just --unset the config that you just tried.

git config --global --unset core.pager
git config --global --unset color.pager

The other option you have is to open your .gitconfig file and delete the lines of config that set your pager.

If you have ever mistyped a git command very close to an existing one you have likely seen this message.

❯ git chekout dev
git: 'chekout' is not a git command. See 'git --help'.

The most similar command is
        checkout

Automatically run the right one #

What you might not have known is that you can configure git to just run this command for you.

# Gives you 0.1 seconds to respond
git config --global help.autocorrect 1

# Gives you 1 seconds to respond
git config --global help.autocorrect 10

# Gives you 5 seconds to respond
git config --global help.autocorrect 50

Fat Fingers Gone #

Now when you typo a git command it will autmatically run after the configured number of tenths of a second.

❯ git chkout get-error
WARNING: You called a Git command named 'chkout', which does not exist.
Continuing in 1.0 seconds, assuming that you meant 'checkout'.
M       pages/blog/how-i-deploy-2021.md
M       pages/hot_tips/001.md
M       pages/templates/gratitude_card.html
M       plugins/index.py
M       plugins/publish_amp.py
M       plugins/render_template_variables.py
M       plugins/youtube.py
M       requirements.txt
M       static/index.html
Switched to branch 'get-error'

My config #

I’m rocking 10 for now just to see how I feel about it, but honestly I cannot think of a time that I have seen the original warning that was not what I wanted. This at least gives me some time to respond if I am unsure.

git config --global help.autocorrect 10

So worktrees, I always thought they were a big scary things. Turns out they are much simpler than I thought.

Myth #1 #

no special setup

I thought you had to be all in or worktrees or normal git, but not both. When I see folks go all in on worktrees they start with a bare repo, while its true this is the way you go all in, its not true that this is required.

Lets make a worktree #

Making a worktree is as easy as making a branch. It’s actually just a branch that lives in another place in your filesystem.

# checkout a new worktree called compare based on main in /tmp/project
git worktree add -b compare /tmp/project main

# checkout a new worktree called compare based on HEAD in /tmp/project
git worktree add -b compare /tmp/project

# checkout a worktree from an existing feature branch in /tmp/project
git worktree add /tmp/project my-existing-feature-branch

The worktree that you create is considered a linked worktree, while the original worktree is called the main worktree

Note that I put this in my tmp directory because I don’t expect it to live very long, my recent use case was to compare two files after a big formatting change. You put these where you want, but dont come at me when your /tmp gets wiped and you loose work.

Myth #2 #

they are hidden mysterious creatures

Just like branches git has some nice commands to help us understand what worktrees we have on our system. Firstly we have something very specific to worktrees to list them out.

git worktree list

gives the output

/home/u_walkews/git/git-work-play  b202442 [main]
/tmp/another                       d9b2cf1 [another]

Even the branch command gives a bit different output for a worktree.

git branch

gives this output, notice the + denotes an actively linked worktree, and the * gives the active branch. If you cd over to the worktree directory, these will switch roles.

+ another
  just-a-branch
* main

You can only checkout a branch in one place #

If you try to checkout a branch that is checked out in a linked worktree, you will be presented with an error, and it will not let you check out a second copy of that branch.

❯ git checkout another
fatal: 'another' is already checked out at '/tmp/another'

Myth #3 #

once you go worktree, you worktree

Once you have worktrees on your system, you have a few ways to get rid of them. Using git’s way feels much superior, but if your a doof like me and didn’t read the manual before you rm /tmp/another -rf you will notice that the worktree is still active. If you run git worktree prune it will clean that right up.

git worktree remove another

rm /tmp/another
git worktree prune

It won’t let you remove if you have changes #

This makes me think that remove is a much safer option. If you have uncommitted changes, git worktree remove will throw an error, and make you commit or use --force to remove the worktree.

❯ git worktree remove another
fatal: 'another' contains modified or untracked files, use --force to delete it

RTFM #

read the friendly manual

There is a ton more information in the man page for worktrees, these are just the parts that seemed really useful to me out of the gate.

man git worktree