Wireshark-dev: Re: [Wireshark-dev] git doesn't like me anymore
From: Guy Harris <gharris@xxxxxxxxx>
Date: Sun, 17 Jan 2021 20:59:32 -0800
On Jan 17, 2021, at 3:43 PM, Fulko Hew <fulko.hew@xxxxxxxxx> wrote:

> The subject line says it all, but it doesn't say why.
> git and I just don't seem to understand one another.

I'm not sure whether *anybody* truly understands Git. :-)

See, for example:

	https://xkcd.com/1597/

(yes, I *have* used the "nuke it from orbit, it's the only way to be sure" strategy on Git repositories in a sufficiently weird messed-up state)

	https://git-man-page-generator.lokaltog.net/

	https://twitter.com/agnoster/status/44636629423497217

But anyway, the way I've made GitLab work (note that committing to Wireshark is a matter of making not only Git, but also GitLab as we're using it, work).  This depends on having a UN*X shell environment; it may be harder to make this work for Windows.

I created a repository in GitLab as a clone/fork of the main Wireshark repository.  I gave it the name "my-wireshark-gitlab-submission-scratchpad", so that anybody who stumbles upon it realizes that it's *not* my own private Idaho^Wversion of Wireshark, and it will *ever ever* be my own private version of Wireshark, it's just something that exists to serve as the place to which I push my Wireshark changes so that I can create pull requests from it.  I also:

	1) set it up so that *nobody* can create pull requests for it (you want to change Wireshark, make it a pull request to the Wireshark repository, not to my sandbox) and *nobody* can file issues against it (you want to file a Wireshark bug or request a Wireshark enhancement, file an issue in the Wireshark repository);

	2) set it up to be mirrored from the main Wireshark repository, so that it tracks changes checked into the main Wireshark repository.

I then created some scripts to be run as Git commands (sometimes it's best to think of Git's "porcelain" as a collection of bathroom fixtures, to be assembled by the user, rather than a fully-furnished bathroom).  I gave them names of the form "git-xxx", because if you have a command (executable or script) named "git-xxx" in your path, the command "git xxx <arguments>" runs "git-xxx <arguments>".

I have:

git-reviewbranch:

#! /bin/sh
#
# Create a branch for the review process for Wireshark.
# This must be done *before* committing any changes.
#

#
# The argument is the name to give the branch for this.
#
if [ $# -ne 1 ]
then
	echo "Usage: git reviewbranch <branch>" 1>&2
	exit 1
fi

#
# Step 1: add my fork as "scratchpad".
# ("upstream" and "downstream" are bogus terms.  I'm sticking with
# "origin" for the master Wireshark repository, as it's where The Truth
# resides, and "scratchpad" My Fork, as it exists solely as a place
# to add changes so that they can be turned into pull requests.)
#
# Yes, it's still called "wireshark.git", even after I renamed it
# (to make sure nobody confuses it for something of use to them).
#
git remote add scratchpad git@xxxxxxxxxx:guyharris/wireshark.git

#
# Step 2: create the branch and check it out.  It should track
# the currently checked-out branch of The Truth.
#
# XXX - is the start point redundant?  If we omit it, will it track
# whatever branch we currently have checked out?
#
start_point=`git status -s -b | sed -n '1s/## .*\.\.\.\(.*\)/\1/p'`
git checkout -b "$1" "$start_point"

If I do "git reviewbranch XXX" in a repository that I've cloned from the main Wireshark repository, it creates a branch in my local repository for a change.

git-doreview:

#! /bin/sh
#
# Start or update a review for Wireshark.
# This must be done *after* committing any changes, and
# git reviewbranch <branch> must have been done *before*
# committing any changes.
#

#
# This takes no arguments.
#
skip_ci=no
if [ $# -eq 1 ]
then
	#
	# If the argument is "skip-ci", skip CI for this change.
	#
	if [ "$1" = "skip-ci" ]
	then
		skip_ci=yes
	else
		echo "Usage: git doreview [ skip-ci ]" 1>&2
		exit 1
	fi
elif [ $# -ne 0 ]
then
	echo "Usage: git doreview [ skip-ci ]" 1>&2
	exit 1
fi

#
# Push the changes to My Fork.
#
if [ "$skip_ci" = "yes" ]
then
	git push -o ci.skip scratchpad +HEAD
else
	git push scratchpad +HEAD
fi

If I've committed changes that I think are ready to review, and then do "git doreview", it will push the change to my forked scratchpad repository, and it will end up in that branch.  If it's the first such "git doreview", a merge request will be created, and a URL on GitLab for the merge request will be printed.  If I've *updated* the commit, it'll update the branch and the merge request.

(Note: "skip-ci" doesn't work.)

git-reviewdone:

#! /bin/sh
#
# Finish a review for Wireshark.
# This must be done *after* the pull request was merged.
#

#
# This takes no arguments.
#
if [ $# -ne 0 ]
then
	echo "Usage: git reviewdone" 1>&2
	exit 1
fi

#
# Get the current branch.
#
current_branch=`git status -s -b | sed -n '1s/## \(.*\)\.\.\..*/\1/p'`
echo "Current branch: $current_branch"

#
# Go back to the branch we're tracking.
#
tracked_branch=`git status -s -b | sed -n '1s;## .*\.\.\.\origin/\([^ ]*\).*;\1;p'`
echo "Tracked branch: $tracked_branch"
git checkout "$tracked_branch"

#
# Pick up changes from the upstream repository and rebase so
# it looks as if any local changes we made were made on top
# of the current tip of that repository.
#
# We aren't doing the "upstream and downstream remote" stuff,
# so we don't have to do weird crap to pull from upstream
# and push back to My Fork, as we're going to erase all
# memory of this change from My Fork.
#
# XXX - in git-update, this used to do git pull followed by git rebase;
# I'm assuming I read the git pull man page correctly and
# that "git pull --rebase" is the equivalent to that.
#
git pull --rebase

#
# Forcibly delete the local branch.
# The remote branch should already be gone.
#
git branch -D "$current_branch"

#
# Remove the remote for My Fork.
#
git remote rm scratchpad

Once the change has been merged, "git reviewdone" will clean up everything left over from doing the review; my local repository goes back to tracking the main Wireshark repository, and the branch created for the merge is removed (it no longer serves any useful purpose).

git-unreviewbranch:

#! /bin/sh
#
# Undo a recent git reviewbranch.
#

#
# This takes no arguments.
#
if [ $# -ne 0 ]
then
	echo "Usage: git unreviewbranch" 1>&2
	exit 1
fi

#
# Get the current branch.
#
current_branch=`git status -s -b | sed -n '1s/## \(.*\)\.\.\..*/\1/p'`
echo "Current branch: $current_branch"

#
# Go back to the branch we're tracking.
#
tracked_branch=`git status -s -b | sed -n '1s;## .*\.\.\.\origin/\([^ ]*\).*;\1;p'`
echo "Tracked branch: $tracked_branch"
git checkout "$tracked_branch"

#
# Forcibly delete the local branch.
# The remote branch should already be gone.
#
git branch -D "$current_branch"

#
# Remove the remote for My Fork.
#
git remote rm scratchpad

This is used if the change hasn't been merged and you want to abandon it; "git unreviewbranch" undoes all the stuff "git reviewbranch" did.