====== git ======
Make the clone of the remote repository.
git clone git@github.com:dblume/get-shit-done
git remote add upstream git://github.com/icambridge/get-shit-done
If it's a huge repo, [[https://github.blog/2020-12-21-get-up-to-speed-with-partial-clone-and-shallow-clone/|consider blobless and single branch and no tags]], like so...
git clone \
--filter=blob:none \
-b main \
--single-branch \
--no-tags \
--shallow-submodules \
--recurse-submodules=os/components/toolchain \
--recurse-submodules=':(exclude)**/porting_kit:' \
git@fake.github.com:project/project.git
Eventually, if you want to add another branch to a single-branch clone:
git remote set-branches --add origin another-branch
Or to de-single-branch-ize a clone:
git remote set-branches origin "*"
===== Creating a new remote repository from an existing local one =====
I created hexbright-factory at [[https://github.com/new]]. Then, to create a new repository on the command line at the local computer:
touch README.md
git init
git add README.md
git commit -m "first commit"
git remote add origin git@github.com:dblume/hexbright-factory.git
git push -u origin main
====== Renaming branches ======
===== Updating both local and remote repos =====
To rename a remote branch:
- Rename the local one.
- Push the deletion of the old name.
- Push the new name.
- git remote prune origin
When someone else renamed a remote branch:
$ git fetch --all # Bring your copy of the remote up-to-date
$ git remote prune origin # (where origin is the name of the shared repo)
==== Creating a branch (and possibly pushing to upstream origin) ====
$ git switch -c new_branch
Switched to a new branch 'new_branch'
That was the same as "''git branch new_branch; git checkout new_branch''"
And now if you want to create that branch name at the remote branch, then:
$ git push --set-upstream origin new_branch
==== Creating a local branch from an existing remote ====
After doing a fetch, and suppose "origin/remote-branch" exists, then just:
$ git switch remote-branch
==== Changing a local branch to a new remote branch ====
This'll work if you don't have a local branch with that name already.
$ git checkout --track origin/branch_name
==== Making the current local branch track a new remote branch ====
$ git branch -u origin/branch_name
===== Updating a local repo after remote's already renamed its branch =====
git branch -m master main
git fetch --all --prune
git branch -u origin/main main
git remote set-head origin -a
====== Fixing a bug in its own branch ======
git switch -c bugfix/JIRA-1-new-bugfix
# If main is getting updated, rebase like so:
# git switch main
# git pull
# git switch bugfix/JIRA-1-new-bugfix
# git rebase main # --dry-run to test first
# Consider whether you want to squash commits before pushing
# git reset --soft HEAD~3 # Moves head back 3, and those 3 become staged
git commit -m "fixed bug"
git push --set-upstream origin bugfix/JIRA-1-new-bugfix
# Do a MR/PR that deletes the original branch at the remote
git switch main
git branch -d bugfix/JIRA-1-new-bugfix
git pull
====== Resolving a Merge Conflict ======
git mergetool (possibly with filename) # Bring up the vim 3-way diff
# +----------+-----------+------------------+
# | (others) | (common) | (my most recent) |
# | LOCAL | BASE | REMOTE |
# +-----------------------------------------+
# | |
# | temp file with <<< ||| >>> diffs |
# +-----------------------------------------+
git commit -a -m "Resolved merge conflict"
Possibly keep rebasing.
git rebase --continue
git pull
====== Alternative to Rebasing: Stash, Pull, Unstash ======
**[[https://roku.slack.com/archives/C453HNABT/p1657224221440529|Problem]]**:
> I attempted to rebase my branch to main and end up pulling in all of the intermediate commits on main into my branch, and the merge request suddenly requires approval from unrelated code owners.
**Workaround**:
Instead of doing a rebase before commit, stash your changes, set the upstream to origin/main, do a pull, unstash the change, then commit and push -f upstream to the branch. Kind of like this:
git stash push -m "hold for pull"
git switch main
git pull
git stash pop # restores stash on top of main
git add/commit
git push -f origin
If others have made changes in the branch you're working on, you can try to rebase directly onto the latest from the remote:
git pull --rebase # --dry-run to test first
====== Applying changes in a stash to a changed file =====
When ''git stash apply'' doesn't work: Show the stash changes and pipe that to patch. Now you have a patch you can apply.
git stash show -p | patch -p0
====== When using Merge Commits instead of Rebasing ======
Use ''--first-parent'' with ''git log''.
====== Two Independent Remotes ======
After you've already set up one remote, ''origin'', and you want to map your ''main'' to ''other-main'' at ''other-origin'', you can do so like:
git remote add other-origin ssh://other.com/project.git
git fetch other-origin
git branch --set-upstream-to=other-origin/other-main main
git pull other-origin other-main --allow-unrelated-histories
git mergetool
... do your pushes and pulls, then to switch back to origin...
git branch --set-upstream-to=origin/main main
====== git at dlma.com ======
I created a remote git repo at dlma like so:
At the server:
git$ mkdir testcode.git
git$ cd testcode.git/
testcode.git$ git init --bare
Then, at the local computer:
testcode$ git init
Initialized empty Git repository in /home/David/testcode/.git/
testcode$ git add .
testcode$ git commit -m "first commit"
...
testcode$ git remote add origin ssh://USERNAME@dlma.com/~/git/testcode.git
testcode$ git push origin main
Options are:
* I chose GitHub-like [[https://github.com/klaussilveira/gitlist|gitlist]] for https://git.dlma.com, because it works on my shared server.
* [[https://www.reddit.com/r/selfhosted/comments/13hxnf4/selfhosted_git_services_you_dont_need_a_huge/|cgit]] might work
* [[https://gogs.io/|gogs]]
* [[https://git-scm.com/book/en/v2/Git-on-the-Server-GitWeb|GitWeb]] (the one built-in.)
====== Limit scope of huge repos ======
Create a .gitconfig file at the base of your repo:
[remote "origin"]
fetch = +refs/heads/main:refs/remotes/origin/main
fetch = +refs/heads/user/dblume/*:refs/remotes/origin/user/dblume/*
tagopt = --no-tags
Or explicitly specify your flags:
git fetch --no-tags origin main
git pull --no-tags origin main
git submodule foreach git pull --no-tags origin main
The submodule one is an optimization for the more general:
git submodule update --recursive # Add --init before --recursive on first time
====== Submodules ======
[[https://www.cyberdemon.org/2024/03/20/submodules.html|Demystifying git submodules]] is [[https://social.jvns.ca/@b0rk/112604915327918216|summarized by Julia Evans in a 'zine page here]].
Cloning a repo doesn't download its submodules. After cloning, run:
git submodule update --init --recursive
Git pull and checkout don't update submodules. To actually update them, you have to run the following every time you switch branches or pull.
git submodule update --recursive # Add --init before --recursive on first time
====== git vim mergetool on macOS ======
File /usr/local/Cellar/git/2.38.1/libexec/git-core/mergetools/vimdiff has this line:
FINAL_CMD="-c \"set hidden diffopt-=hiddenoff | $CMD | tabfirst\""
But vim has a problem with "diffopt-=hiddenoff"