Lesson 7: Experiences, bugs, and merge experience

Claude

2024-11-27

Planning

  • 4 December no N2G
  • 11 December lesson 8
  • 18 December (probably) lesson 9
  • ???

I owed you from last week

I tried to explain last week the situation when the remote and the local branch diverge.

There are three branches that we care about (in this example main but can be anything):

  • The main branch on GitHub
  • The remotes/origin/main branch locally (aka origin/main)
  • The main branch locally

There can be 500 other people having main branches, but those are their problems. You only care about these three.

(Recap: fast forward)

Fast-forward means that commits from branch B are added to branch A without any rewrite. This is only possible if A is an ancestor of B.

Fast-forward is possible:

%%{init: { 'logLevel': 'debug', 'gitGraph': {'showBranches': true, 'showCommitLabel':true,'mainBranchName': 'A'}, 'theme': 'default' , 'themeVariables': {
              'git0': '#ff0000',
              'git1': '#00ff00',
              'git2': '#0000ff',
              'git3': '#ff00ff',
              'git4': '#00ffff',
              'git5': '#ffff00',
              'git6': '#ff00ff',
              'git7': '#00ffff'
       } } }%%
gitGraph
  commit
  commit
  branch B
  commit
  commit

Fast-forward is not possible:

%%{init: { 'logLevel': 'debug', 'gitGraph': {'showBranches': true, 'showCommitLabel':true,'mainBranchName': 'A'}, 'theme': 'default' , 'themeVariables': {
              'git0': '#ff0000',
              'git1': '#00ff00',
              'git2': '#0000ff',
              'git3': '#ff00ff',
              'git4': '#00ffff',
              'git5': '#ffff00',
              'git6': '#ff00ff',
              'git7': '#00ffff'
       } } }%%
gitGraph
  commit
  commit
  branch B
  commit
  commit
  checkout A
  commit

We should realise how these branches work together:

flowchart LR
    A(GitHub main) -->|fetch| B(origin/main)
    B -->|pull| C(local main)
    C -->|push| A

  • fetch fetches any changes from GitHub to origin/main. Since GitHub main can only get more commits added (unless push -f), this fetch is always a fast-forward (however if not, fetch does not care, it just copies whatever is the GitHub main branch).
  • push pushes your local branch to GitHub. (if not -f) this will only succeed if this is a fast-forward. Else it will fail (and tell you to pull first). push will also do a fetch after the push, so that origin/main is also up-to-date.
  • pull first does a fetch and then somehow combines origin/main and main. The goal of pull is to make GitHub main (=origin/main after a fetch) an ancestor of main.

Three options

No changes in origin/main –> nothing to do in pull:

flowchart LR
  A((A)) --> B((B)) --> C((C)) --> D((D))
  D --o originmain>origin/main]
  D --> E((E)) --> F((F))
  F --o main>main]

No changes in main –> pull can just fast-forward main:

flowchart LR
  A((A)) --> B((B)) --> C((C)) --> D((D)) --> E((E)) --> F((F))
  F --o originmain>origin/main]
  D --o main>main]

The branches have diverged:

flowchart LR
  A((A)) --> B((B)) --> C((C)) --> D((D)) --> E((E)) --> F((F)) --o originmain>origin/main]
  D --> G((G)) --> H((H)) --o main>main]

pull --no-rebase (merge)

Before:

flowchart LR
  A((A)) --> B((B)) --> C((C)) --> D((D)) --> E((E)) --> F((F)) --o originmain>origin/main]
  D --> G((G)) --> H((H)) --o main>main]

After:

flowchart LR
  A((A)) --> B((B)) --> C((C)) --> D((D)) --> E((E)) --> F((F)) --o originmain>origin/main]
  D --> G((G)) --> H((H)) --> M((M)) --o main>main]
  F --> M

After merge, origin/main can be fast-forwarded to main (F is ancestor of main); since origin/main is a copy of GitHub main, push to GitHub main should work (unless someone else just pushed).

pull --rebase

Before:

flowchart LR
  A((A)) --> B((B)) --> C((C)) --> D((D)) --> E((E)) --> F((F)) --o originmain>origin/main]
  D --> G((G)) --> H((H)) --o main>main]

Step 1:

flowchart LR
  A((A)) --> B((B)) --> C((C)) --> D((D)) --> E((E)) --> F((F)) --o originmain>origin/main]
  E --> G1((G*)) --> H1((H*)) --o main>main]

Step 2 (etc, 1 step per commit):

flowchart LR
  A((A)) --> B((B)) --> C((C)) --> D((D)) --> E((E)) --> F((F)) --o originmain>origin/main]
  F --> G2((G**)) --> H2((H**)) --o main>main]

Actually:

flowchart LR
  A((A)) --> B((B)) --> C((C)) --> D((D)) --> E((E)) --> F((F)) --o originmain>origin/main]
  D --> G((G)) --> H((H)) --o main>main]

git pull --rebase

flowchart LR
  A((A)) --> B((B)) --> C((C)) --> D((D)) --> E((E)) --> F((F)) --o originmain>origin/main]
  D --> G((G)) --> H((H)) --- orph1(orphaned)
  E --> G1((G*)) --> H1((H*)) --- orph2(orphaned)
  F --> G2((G**)) --> H2((H**)) --o main>main]

The first time you pull in a repository, git asks what strategy you want to use:

hint: You have divergent branches and need to specify how to reconcile them.
hint: You can do so by running one of the following commands sometime before
hint: your next pull:
hint:
hint:   git config pull.rebase false  # merge
hint:   git config pull.rebase true   # rebase
hint:   git config pull.ff only       # fast-forward only
hint:
hint: You can replace "git config" with "git config --global" to set a default
hint: preference for all repositories. You can also pass --rebase, --no-rebase,
hint: or --ff-only on the command line to override the configured default per
hint: invocation.

If you choose “fast-forward only”, it just means that a pull will fail if there are diverging branches.

Bugs (= error / mistake / problem)

In the 1940’s actual bugs would crawl into (nice and warm) computers: “First actual case of bug being found” (1947)

“Unfortunately” the term “bug” predates this (Edison was using it).

Issues

  • GitHub has several interesting tools, among which an issue tracker (aka bugtracker)
  • Different kinds of issues (important to diffrentiate):
    • Bugs (error messages, obvious errors, “documentation says A, it does B”)
    • Feature requests / enhancement
    • Questions
  • Important to understand that “code does not do what I want” is not a bug, usually a FR.
  • Important to properly describe what you want. This week I received bug reports / questions:
    • “push does not work”
    • “I cannot pull the code after cloning it”
    • “Nano does not let me save”

A good bug report:

  • Minimal steps / code to reproduce
  • What version of the product (ideally you check on the latest version)
  • Description of parts of your system that make sense (e.g. mention which R version you have and which packages you have installed).
  • Screenshots are often helpful
  • However copy the error / output as text (to simplify finding this issue in the future)
  • Make sure you have a good title that explains what it’s about (in a list of 200 issues). “Bug” or “Broken” is not a good title.
  • If the person will be able to fix the issue / answer the question in 10 minutes without having to ask more information, it’s much more likely that it will be picked up.

GitHub issue properties

  • Title
  • Description (incl images)
  • Timeline (discussion, mention, events)
  • State (Open or closed)
  • Assignees (0 or more, incl yourself)
  • Labels (0 or more)
  • Projects
  • Milestone
  • Development (branch or PR)

Normal search only shows open issues

Built in labels

Type:

  • bug
  • enhancement
  • question

Extra info:

  • good first issue
  • help wanted
  • documentation

Resolution:

  • duplicate
  • invalid
  • wontfix

GitHub issues etiquettes

  • It’s completely OK (and even encouraged) to point out mistakes in some complete stranger’s code / documentation (but be respectful).
  • Even if you think it’s a stupid mistake that never should have been made, it may have evolved over time.
  • Remember that the person maintaining the code probably does so in their free time, and may have other priorities. Usually they will take time to reply to a (well made) issue, but not necessarily want to spend more than 5 minutes right now (often they promise time “in a couple of weeks” – we all know when that is. It’s considered nice to make a pull request in that case (if your fix is generally useful). _ I personally spend at least an hour on a problem / bug before I post it to someone else’s repo. Sometimes it’s hard to spend this time knowing that there is a chance that the owner does not care / will not answer, still it’s worth it.
  • Remember that you’re asking a random person to do some work for you (even if it’s just answering your question). An attitude “I don’t have time to narrow down the root cause of this issue, but I’m asking you to do it” usually doesn’t get you far.

More GitHub issues etiquettes

  • Honey catches more flies than vinegar
  • If the repo owner does not agree with you / does not want to fix your issue, assume they are right. They probably thought more about the subject matter than you. And even if they are wrong, it’s unlikely you will convince them.
  • You can always fork the repository and make your own fix (and use that).

“GitHub issues” superpowers

  • Make issues directly from code
  • Make issues directly from diffs
  • Refer to a commit in your bug
  • Connect a development branch / PR to an issue
  • Refer to issues in commits (and even close them in a commit)
  • use @username to derectly involve someone

What was the experience from last week’s homework

It was meant to be furstrating some times, and mistakes were meant to be made.

(I look at how Audrey learns, and assume all humans are the same ;))

I know that 10 minutes per day was maybe a bit optimistic, but we need to get there.

If it takes you 20 minutes to make a commit, you are never going to do it.

It should be: yes I want to come for lunch, let me just commit this ….. there ….. done.

Anyways, let’s go through what happened in the repository. In order to learn from each other’s challenges!

I would like everyone to make an issue in the repo, assign it to someone. Please make it small enough to fix in 2 minutes.

Discussion: what’s next

  • More recipes
  • Welcome to Gdansk guide
  • Fieldwork guide
  • Manuscript guide
  • Git game :)

Playtime: Make Quarto Website

(aka: merge experience)

We’re going the play around a bit. We do this in a Quarto Website in RStudio (but things would be equally valid in other editors / other code). We will use the commandline for all git stuff. You may certainly do this same exercise again later using the built-in tools in RStudio.

Step 1

Create a new project “Recipes” in RStudio, Quarto Website. Check the box “Create a git repository”.

Note

We could initialize the git repository in the commandline interface as well using git init. However RStudio also populates .gitignore for us. Let’s quickly look at this file to see what RStudio put in there for us.

Step 2

  • Press “Render” and see that you have a website (it might need to install some stuff).
  • In Rstudio, click “render on save”.
  • Change the title of the website in _quarto.yaml and save. See the result.
  • Change index.qmd to a nice welcome page: “Welcome to Claude’s kitchen” (or what you want). If you feel brave, add an image, save and check.
  • Change about.qmd and write 2 lines about the website, and add some bullet points. Then save and check.
  • Click the “Source” button to see the actual file content (Markdown).

Now that we have something, let’s commit a first version (using the cli). Make sure no files that should not get checked in are checked in!

Also let’s cat the about.qmd file, just to make sure it’s text.

Note

In the documentation Quarto seems to suggest that the file extensions should be .Qdm, but by default they are .qmd. Personally I don’t like using capitals in extensions, but both seem to work equally well.

Step 3

  • Add three pages to the website for some recipes (applepie.qmd, mojito.qmd, cheese-fondue.qmd); go to “File -> New File -> Quarto Document”, then save it with the right file name. Copy-paste some recipe into each of them (doesn’t have to be the right one, but three different ones). Note that you may have to click “refresh” on your files-overview.
  • Create links to the recipes on the index.qmd: (Using: “Insert -> Link” and appliepie.qmd as file name, or [Aplepie](applepie.qmd) in Markdown). NOTE: intensionally make a typo in one of the link texts (not the filename to which you link).
  • Save, check, and commit.

Step 4

  • Create a branch layout-experiments
  • Create a branch vegan
  • Create a branch typos
  • In main we make one more recipe (be creative). Commit
  • In branch layout-experiments, experiment with a new theme (see https://quarto.org/docs/output-formats/html-themes.html, change in _quarto.yml, you will have to manually press “Render” again to check) and commit.
  • In branch layout-experiments, add a emoji to each link on index.qdm and commit
  • In branch vegan, change your recipes to be vegan and commit
  • In branch typos, fix the typo that I made you make in step 3 (if you did not, just imagine there is a typo and “fix” it).

Step 5

We have this, time to merge

gitGraph
  commit
  commit
  branch layout-experiments
  branch vegan
  branch typos
  checkout main
  commit
  checkout layout-experiments
  commit
  commit
  checkout vegan
  commit
  checkout typos
  commit

  • Merge vegan into main. Feel free to delete the vegan branch afterwards.

Step 6

gitGraph
  commit
  commit
  branch layout-experiments
  branch vegan
  branch typos
  checkout main
  commit
  checkout layout-experiments
  commit
  commit
  checkout vegan
  commit
  checkout typos
  commit
  checkout main
  merge vegan

  • Merge layout-experiments into main. Feel free to delete the branch afterwards.

Step 7

gitGraph
  commit
  commit
  branch layout-experiments
  branch vegan
  branch typos
  checkout main
  commit
  checkout layout-experiments
  commit
  commit
  checkout vegan
  commit
  checkout typos
  commit
  checkout main
  merge vegan
  merge layout-experiments

  • Merge typos into main. This will fail. Use git status to check which files are the problem, and manually fix these files. Then add the file and commit (see next page).
$ git merge typos
Auto-merging index.qmd
CONFLICT (content): Merge conflict in index.qmd
Automatic merge failed; fix conflicts and then commit the result.
# There is a conflict because the same line was edited in multiple revisions.
$ git status
On branch main
You have unmerged paths.
  (fix conflicts and run "git commit")
  (use "git merge --abort" to abort the merge)

Unmerged paths:
  (use "git add <file>..." to mark resolution)
    both modified:   index.qmd

no changes added to commit (use "git add" and/or "git commit -a")
# Manually edit `index.qmd`. Note that RStudio is actually smart enough to detect the conflict markers and offer you the markdown version to fix the error. Fix it and save the correct version.

$ git add index.qmd
$ git commit
[main 1ff5925] Merge branch 'typos'
# Note that `git commit` already has "Merge branch `typos`" filled in as commit message. It remembered that it was doing that.

Done