Repository navigation
Git
MidnightBSD moved to git in early 2020 for all development.
git clone https://github.com/MidnightBSD/src.git(also works with svn or svnlite with github)
git clone [email protected]:MidnightBSD/src.gitgit clone https://github.com/MidnightBSD/mports.gitgit clone [email protected]:MidnightBSD/mports.gitThere are at least two methods here. The first is to use git config and the second is environment variables.
git config --global user.name "John Doe"
git config --global user.email "[email protected]"If you only want it for the current repo, don't use the --global
If you screw up a commit and need to fix it before setting this
git commit --amend --author="John Doe <[email protected]>"It's global and overrides any git config settings, at least in some versions of git.
export GIT_AUTHOR_NAME="Midnight the Cat"
export GIT_AUTHOR_EMAIL="midnight@localhost"(assuming you've cloned and are in the directory)
Change to the stable 1.2 branch
git checkout stable/1.2
See what branch you're on and other local branches as well as the most recent commit on them git branch -v
(assumes remote is called origin)
git remote show origin
It's best to read up on this one. https://git-scm.com/book/en/v2/Git-Tools-Rewriting-History#Changing-Multiple-Commit-Messages
This will walk you through each commit starting at the one you specified, which should be the last "good" commit.
git rebase -i -p 0ad14ff3
For example, if you want to fix author info:
git commit --amend --author="John Doe <[email protected]>" --no-edit
git rebase --continue
Renaming Remote Branches
rename locally
git checkout old-branch
git branch -m new-nameverify name
git branch -a
rename remote (assumes previous steps for local)
git push origin --delete old-name
git push origin -u new-namegit push remote_name -d remote_branch_name
If you start seeing ESC[ type escape sequences with git commands, you likely need to fix your pager.
One solution is
git config --global core.pager "less -R"Patch for a specific commit
git format-patch -1 <sha>src committers need to make vendor branches to track third-party code.
The first option starts with creating a new directory and git repo outside the src directory.
cd /some/where
mkdir foo
cd foo
git init
git checkout -b vendor/fooThe second option instead is to just run
git checkout --orphan vendor/foocp -R ~/foo/ .
git add -A -f
git commit -m "Import foo 1.0"Use git add -A -f, not git add * or plain git add -A. The * glob skips
dot files such as .gitignore, and both forms skip anything matched by a
.gitignore in the upstream sources. See "Ignored files in upstream sources"
below.
cd /usr/src
git remote add foo /some/where/foo
git fetch foo vendor/foogit worktree add ../foo vendor/foo
cd ../foo
git tag --annotate vendor/foo/1.0
git show
git push --follow-tags origin vendor/foocd ../src
git subtree add -P contrib/foo vendor/foo
git show
git commit --amend
git push origingit worktree add ../foo vendor/foo
cd ../foo
rsync -va --no-o --no-g --del --exclude=".git" ~/git/foo/ .
git add -A -f
git status
git diff --staged
git commit -m "Vendor import of foo 1.0"Notes:
- The trailing slash on
~/git/foo/matters: without it rsync copies into./foo/fooinstead of replacing the worktree contents. -
--no-o --no-gstops rsync from copying the tarball's owner onto the worktree. Otherwise git may refuse the directory with a "dubious ownership" error. - If the upstream source is a git clone, export the release tag with
git --work-tree=/path/to/export checkout v1.0 -- .rather thangit archive.git archiveleaves out files that upstream marksexport-ignorein.gitattributes.
Many upstream projects ship a .gitignore. Once it is copied into the vendor
worktree, git applies it, and a plain git add -A silently skips every file it
matches. Nothing warns you: the files just never make it into the vendor
branch. For example, libarchive's .gitignore contains *.cmake and
Makefile, so every libarchive import before 3.8.11 was missing
CTestConfig.cmake, contrib/shar/Makefile and examples/minitar/Makefile.
Always stage vendor imports with -f, which adds ignored files too:
git add -A -fTo see whether a .gitignore is hiding anything before you stage:
git status --ignored --short | grep '^!!'To check afterwards that every upstream file was staged, compare the staged files with the upstream tree:
git ls-files | sort > /tmp/staged.txt
(cd ~/git/foo && find . -type f ! -path './.git/*' | sed 's|^\./||' | sort) \
> /tmp/upstream.txt
comm -13 /tmp/staged.txt /tmp/upstream.txtcomm -13 prints files that are in upstream but not staged. The list should be
empty, or contain only files you deliberately prune (see the package's
MIDNIGHTBSD-Xlist).
If upstream is a git clone and you prune nothing, comparing tree hashes is quicker. The two hashes should be identical:
git write-tree # in the vendor worktree
git -C ~/git/foo rev-parse 'v1.0^{tree}' # upstream release taggit tag -a vendor/foo/1.0
git push --follow-tags origin vendor/foocd ../src
git subtree merge -P contrib/foo vendor/fooThe merge commit must keep the vendor commit as its second parent. Git uses that link to find the merge base the next time you merge from the vendor branch.
If the update goes through a pull request, merge it with Create a merge commit. Never use Squash and merge or Rebase and merge, and say so in the PR description. A squash turns the merge into an ordinary single-parent commit, so the vendor commit is no longer an ancestor of master.
Nothing looks wrong at first. The trouble comes with the next update:
git subtree merge picks an older import as the base and reports large
numbers of false conflicts. This happened with libarchive 3.8.8 (PR #451),
and the 3.8.11 merge hit 54 bogus conflicts.
Before pushing, check that the vendor commit is an ancestor of the branch:
git merge-base --is-ancestor vendor/foo master && echo okIf an earlier import was squashed, merge using the previous vendor tree as the
base. Build two temporary commits on top of master, one with contrib/foo
replaced by the old vendor tree and one with the new tree, then three-way merge
them:
old=$(git rev-parse vendor/foo/1.0^{tree}) # last import that was squashed
new=$(git rev-parse vendor/foo/1.1^{tree}) # import being merged
for v in old new; do
eval t=\$$v
GIT_INDEX_FILE=/tmp/idx.$v git read-tree master
GIT_INDEX_FILE=/tmp/idx.$v git rm -r -q -f --cached contrib/foo
GIT_INDEX_FILE=/tmp/idx.$v git read-tree --prefix=contrib/foo/ $t
eval c_$v=$(GIT_INDEX_FILE=/tmp/idx.$v git write-tree |
xargs -I{} git commit-tree {} -p master -m tmp)
done
git merge-tree --write-tree --merge-base=$c_old master $c_newgit merge-tree prints the merged tree and lists any conflicts. Resolve the
conflicts, then record the result as a merge commit with master as the first
parent and the vendor commit as the second (git commit-tree <tree> -p master -p vendor/foo). Later merges then work normally again.
git worktree remove foo