Project setup and reproducibility
The shared mechanics behind both group projects
What this page is for
Both group projects use the same repository structure, the same .gitignore, the same documentation files, and the same reproducibility test. Rather than say all of that twice, it lives here.
You do not need to read this end to end before starting. Work through Setting up the repository in your project’s first week, then come back to the other sections as you reach them. The project brief tells you when.
The starter zip does most of this for you. Download the one for your project — Project 1 or Project 2 — and you begin with the structure, the .gitignore, and the documentation templates already in place. What follows is what those files are for, so you can use them well rather than just having them.
Repository structure
Your team’s repository has this structure — and you do not have to build it by hand. project-1-starter.zip contains all of it, ready to unzip:
project-1-team-name/
│
├── README.md
├── .gitignore
├── project-1-team-name.Rproj # you create this in RStudio; named after your folder
│
├── data/
│ ├── README.md
│ ├── raw/ # local only / ignored by Git
│ └── derived/ # local only / ignored by Git
│
├── documentation/
│ ├── project-plan.md
│ ├── data-provenance.md
│ └── codebook.csv
│
├── programs/
│ ├── p1_data_brief.qmd
│ └── p1_data_brief.html # renders here, next to its source
│
└── output/
└── figures/ # exported .png files, if you save any
The exact repository name is up to your team. The structure is not — keeping everyone on the same structure is what makes the project easier to read, troubleshoot, and grade. (Project 2’s repository looks the same, with p2_reproduction.qmd in programs/ plus a few extra files its starter ships: documentation/reproduction-plan.md, and the references.bib + apa.csl citation machinery from your M08 paper.)
The rendered report lives beside its .qmd, exactly as in every lab
Quarto writes report.html next to report.qmd. That is what has happened in every lab since M02, and nothing changes here — do not move the HTML into output/, and do not add output-dir: to the YAML to redirect it. Keeping the source and its render in one folder is what makes “re-render and see” a single click.
output/figures/ is for something different: figures you deliberately export as standalone .png files. You met the tool in M03 — the Data Visualization module shows ggsave() with here() and explains why you set the width and height at save time. Here it is with this project’s path:
ggsave(here("output", "figures", "fig1-prevalence-by-group.png"),
my_plot, width = 6.5, height = 3.6, dpi = 300)M03’s example writes straight into output/; here you add a figures/ subfolder, because a project accumulates more exported files than a single lab does and they are easier to find grouped together.
Note the filename: fig1-prevalence-by-group.png, not Figure 1 final.png. No spaces in anything you name — the reasons are in No spaces in any name you create below — and a name that says what the figure shows saves you opening three files to find the right one.
Note here() doing the work: the path resolves from the project root, so it is the same string on every teammate’s laptop.
Whether you need this at all depends on your presentation. If you present by scrolling the rendered report, every figure is already in it and output/figures/ may hold nothing but its .gitkeep — that is a perfectly good outcome. If you build slides, exporting the figures you want to show is easier than screenshotting them.
Two things follow, and both matter now that we grade the repository:
- The rendered
.htmlstays untracked until the very end. Your.gitignoreexcludesprograms/*.htmlon purpose — see Why the rendered report is ignored while you work below. It is still part of the deliverable; it just gets committed once, by one person, in your final week. - The report is self-contained. The template sets
embed-resources: true, so the HTML bundles its own images and styles into one file. That is why excluding*_files/is safe, and why we can open your report straight from GitHub without anything else.
Setting it up · step by step
We give you the skeleton. Download project-1-starter.zip — it contains the folder structure above, the .gitignore, the documentation templates, and the report skeleton, all ready to go.
That is deliberate. Clicking New Folder five times teaches you nothing, and the .gitignore in particular is a file you need to understand, not to retype. What the starter does not do is make it a repository or publish it — those are the Git skills, and they are yours.
1 · One person sets up the folder. Pick a repo owner (an administrative role only — no extra authority over the analysis). Everything in this step happens on that person’s laptop.
a. Unzip the starter somewhere you will find it again — alongside your PSY652_project folder is a good choice, not inside it.
b. Rename the unzipped folder for your team, with no spaces: project-1-team-name.
No spaces in any name you create
This is the first name you choose, and the rule holds for every one after it — the project folder, exported figures, derived data files, anything you name yourself.
| Not this | This |
|---|---|
project 1 team name/ |
project-1-team-name/ |
Figure 1 final.png |
fig1-trust-by-age.png |
clean data.rds |
analytic.rds |
Three reasons the habit is worth forming now:
- GitHub will not keep the spaces. Repository names cannot contain them, so a folder named with spaces publishes under a different name than the one on your laptop — and the mismatch is confusing exactly when you are trying to help a teammate find something.
- Paths with spaces have to be quoted, and anything that forgets to quote them fails with an error that never mentions spaces. You lose the time to the diagnosis, not the fix.
- A space becomes
%20in a URL, so any link to the file — including the one your teammate clicks in GitHub — comes out unreadable.
Stick to lowercase letters, digits, hyphens, and underscores, with a single . before the extension.
c. Open it in RStudio. File → New Project → Existing Directory, point at the folder, and click Create Project. Use this menu path — do not create the .Rproj file yourself. Making a file named .Rproj in Finder or Explorer looks like it should work, but only RStudio’s Create Project actually turns the folder into a project. The starter’s setup chunk checks, and tells you if the folder is not a project yet. RStudio reopens with that folder as the working directory and creates an .Rproj file named after it — so project-1-team-name.Rproj. That file is what makes here() resolve from anywhere inside the project.
d. Turn on hidden files, and check what you got. Two of the most important files in the project start with a dot, which means your file browser hides them by default. In RStudio’s Files pane click More (the gear icon) → Show Hidden Files. Leave it on for the rest of the project.
You should now see .gitignore at the top level and a .gitkeep inside data/raw/, data/derived/, and output/figures/. Compare the whole thing against the tree above before moving on.
What those two dotfiles are doing
.gitignore lists what Git should leave alone — above all, your data. Read the next section before your first commit; it is short, and it is the difference between a clean repository and one with a survey file permanently baked into its history.
.gitkeep is a placeholder, and it exists because of a quirk worth knowing: Git tracks files, not folders. An empty folder cannot be committed at all, so without these your teammates would clone the project and find data/raw/ simply missing — then follow data/README.md, be told to put the raw file there, and have nowhere to put it. The .gitkeep files are empty on purpose. Leave them.
2 · Make it a repository and publish it. Open GitHub Desktop → File → Add Local Repository, choose your folder, and follow the same create a repository prompt you met in the M02 lab. Then click Publish repository and choose Private.
3 · Add the instructors, and invite your teammates. Do this as soon as the repository exists, not at the end — your project plan is due at the close of the project’s first week and we read it there, which we cannot do from outside a private repository. On github.com add KimberlyHenry and alliekom as collaborators, then your teammates. Each teammate clones through GitHub Desktop. Full steps, with the menu paths, are in Collaborating with Git — read that page before your first shared work session, not after your first conflict.
Check this before you commit anything
Open GitHub Desktop and look at the Changes list. If you can see a data file under data/raw/ or data/derived/ — a .sav, a .csv, an .rds — your .gitignore is not doing its job, so stop and fix it before committing. Once a data file is in the history, removing it is genuinely difficult, and for restricted data it may be impossible to undo.
What you should see listed: README.md, .gitignore, the .Rproj you just created, data/README.md, the three .gitkeep placeholders, the documentation/ templates, and programs/p1_data_brief.qmd.
The .gitkeep files belong there — they are how the empty folders survive a clone. Seeing data/raw/.gitkeep is the ignore rule working correctly; seeing data/raw/atp-w####.sav is not.
Your .gitignore
The starter already contains this file at the top level of the repository. Open it before your first commit and check that it matches the version below.
.gitignore
# ---- Data: never commit ----------------------------------------------------
# Raw files are often large, sometimes restricted, and always re-obtainable
# from documentation/data-provenance.md -- whether you downloaded them from Pew
# or from a paper's data repository. Derived files are rebuilt by your code.
# The trailing /* ignores each folder's CONTENTS rather than the folder itself.
data/raw/*
data/derived/*
# ...but DO track the placeholders, so a fresh clone still has somewhere to put
# the source file and somewhere for your code to write the derived one.
# The leading ! un-ignores a path that an earlier rule excluded.
!data/raw/.gitkeep
!data/derived/.gitkeep
# ---- R and RStudio ---------------------------------------------------------
.Rproj.user/
.Rhistory
.RData
.Ruserdata
# ---- Quarto ----------------------------------------------------------------
/.quarto/
*_files/
*_cache/
# ---- The rendered report: ignored WHILE YOU ARE WORKING ---------------------
# Your report regenerates every time anyone renders, and embed-resources bakes
# the figures into it -- so two teammates' renders are never byte-identical and
# Git cannot merge them. Keeping it untracked while you iterate removes the most
# common conflict on this project entirely.
#
# BEFORE YOU SUBMIT: delete the single line below, have ONE person render, and
# commit the result. The rendered report is part of what we grade.
programs/*.html
# ---- Operating system junk -------------------------------------------------
.DS_Store
Thumbs.dbThe two ! lines are the ones people get wrong — and the reason is a rule about Git that is worth knowing now rather than discovering during your clean-clone test. Git tracks files, not folders. An empty folder cannot be committed at all, which is why the starter ships a .gitkeep inside each folder that would otherwise be empty.
That creates a trap. If the ignore rule were written data/raw/ — the whole folder — it would swallow the .gitkeep inside it too, and the folder would vanish on a fresh clone. Your teammate would follow data/README.md, be told to put the raw file in data/raw/, and find no such folder. Writing data/raw/* instead ignores the folder’s contents while leaving the placeholder un-ignorable by the following ! line.
Note that data/README.md needs no ! rule of its own: nothing here ignores data/ itself, only what sits inside raw/ and derived/, so that file is tracked already.
Why this differs from your course project’s .gitignore. That one ignores a single flat data/ folder, because everything in it arrived ready to use. Yours has to distinguish the raw file you downloaded from the analytic file your code builds — and keep a tracked note explaining both.
Why the rendered report is ignored while you work
Your .gitignore excludes programs/*.html, and that line is the single biggest headache-preventer in the file.
The report regenerates every time anyone renders, and embed-resources: true bakes the figures into it as one large file. Two teammates rendering the same source do not produce the same bytes — different machines, fonts, and package versions see to that. So if the HTML were tracked, every push after a teammate’s push would collide on it, and Git cannot merge a forty-thousand-line generated file. You would be resolving a conflict about something neither of you actually changed.
Keeping it untracked while you iterate removes that entirely. Nobody needs the rendered file in the repository during the project anyway: teammates render locally to check their own work, and we read your project plan in Week 1 and the report after the deadline.
In your final week, put it back
The rendered report is part of what we grade. So once the analysis is finished:
- Open
.gitignoreand delete theprograms/*.htmlline (leave the rest alone). - Have one person do the final render.
- Commit the
.htmland push.
One person, once — that is what keeps it conflict-free. Both project checklists carry this step; it is an easy one to forget on the last day.
A note on your course project’s .gitignore. That one ends with output/ and *.html, and ignores a single flat data/ folder rather than splitting raw from derived. The reasoning is the same family — generated files regenerate from source — but the lab workflow submits the rendered file to Canvas, whereas here it ends up in the repository at the end. Do not copy lines between the two files; each is already correct for its own project.
The documentation files
README.md · the front door
Your repository has two files named README.md, and they are not the same file. This one sits at the top level and introduces the whole project to a reader who has just arrived. The other lives in data/ and does one small job — telling that reader what belongs in the two data folders they will find empty. Both are tracked by Git, both are yours to fill in, and neither substitutes for the other. The data/ one gets its own section below.
Your starter ships a README skeleton already tailored to your project — Project 2’s names its own report file and asks for the published result it reproduced, where Project 1’s asks for the research question. The shape below is Project 1’s; fill in whichever one you were given.
Your repository README must contain:
# Project title
Team members
## Research question
## Project summary
One short paragraph describing the question and main finding.
## Repository structure
- `programs/` — your Quarto analysis **and the HTML it renders to**
- `documentation/` — project plan, provenance, and analytic codebook
- `data/` — local raw and derived data, not tracked by Git; `data/README.md` says what belongs there
- `output/figures/` — any figures you export with `ggsave()`, for reuse outside the report
## Reproduce this project
1. Clone the repository.
2. Obtain the data using `documentation/data-provenance.md`.
3. Place the raw file at the documented path.
4. Open the `.Rproj` file.
5. Render `programs/p1_data_brief.qmd`.
## Required R packages
[List the packages actually used.]
## Data availability
Explain why the raw data are or are not included in Git.
## Reproducibility check
Clean-clone test completed by [name] on [YYYY-MM-DD].
Cloned fresh, obtained the raw data as documented above, and rendered
`programs/p1_data_brief.qmd` from a restarted R session without errors.documentation/data-provenance.md · where the data came from
This file answers one question: could someone else obtain exactly the file you analyzed? Fill in every line; write “not applicable” rather than leaving a blank.
documentation/data-provenance.md
# Data provenance
## Source
Pew Research Center, American Trends Panel
## Wave
Wave [number] — [official wave name, if it has one]
## Field dates
[Start date] to [end date]
## Report or page that led us here
[Title]
[URL]
## Download URL
[The exact page you downloaded from, not just pewresearch.org]
## Date accessed
[YYYY-MM-DD]
## Downloaded filename
[The filename exactly as it arrived, before any renaming]
## Registration or data-use requirements
[What you had to agree to. Pew requires an account and acceptance of terms.]
## Expected local path
data/raw/[filename]
## Redistribution
[May this file be shared publicly? Course policy for Pew ATP: do not
commit or redistribute the microdata. Each teammate obtains the wave
from Pew under their own account and places it in data/raw/.]
## Notes
[Anything a future reader would need: a wave that was re-released,
a codebook that lives in a separate download, an oddity you noticed.]Write this the day you download the file, not at the end. Access dates and exact filenames are the first things people forget, and they are the two that make a file findable again.
documentation/project-plan.md · what you set out to do
Your Week 1 proposal, kept in the repository and updated as the project develops. It exists so that a reader — and your future selves — can see what you intended before you saw any results.
documentation/project-plan.md
# Project plan
## Team
[Names, and who is taking first responsibility for which section]
**How we will work together**
- *Meeting rhythm:* [when and where you will meet — a standing time beats "we'll message each other"]
- *If someone goes quiet:* [how long you wait before checking in, and who tells the instructor — agree this now, while it is hypothetical]
## Topic
[The substantive issue]
## Research question
[One focused descriptive question]
## Intended reader
[Who would benefit from knowing the answer, and why]
## ATP wave
[Wave number and why it can answer the question]
## Focal variables
[Raw Pew variable names, with a short description of each]
## Planned comparison
[The subgroup, cross-tab, or second dimension you expect to use]
## Survey weight
[The wave-specific weight variable name, even if you analyze unweighted]
## Measurement question we already have
[One honest uncertainty about how the construct was measured]
## Feasibility
[One sentence: why this fits in four weeks with M01–M05 tools]
## Changes to this plan
[Append-only. Date each change and say why it happened.
"2026-10-02 — dropped the income comparison; too much missingness."]That last section matters more than it looks. Plans change for good reasons, and a documented change is a sign of a thoughtful team. An undocumented change makes it much harder for a reader to tell what happened and why.
data/README.md · what belongs in the data folders
This is the second of your two READMEs — not the front door above, but the small note inside data/. It is the only thing in that folder GitHub will show, and without it someone cloning your repository finds two empty folders and no instructions.
data/README.md
# Data
The data files themselves are **not** tracked by Git. This file is.
## data/raw/
The file exactly as downloaded, never edited by hand.
Expected file: `[filename]`
To obtain it, follow `documentation/data-provenance.md`.
## data/derived/
The analytic dataset, built from the raw file by
`programs/p1_data_brief.qmd`. Do not edit by hand — if something is
wrong, fix the code and re-render.
Expected file: `analytic.rds`
## If you just cloned this repository
Both folders will be empty. Obtain the raw file, place it in
`data/raw/`, then render `programs/p1_data_brief.qmd` — it rebuilds
`data/derived/` for you.documentation/codebook.csv · what the analytic variables mean
Use the project codebook format — seven columns:
variable,description,type,values,missing,source,derivation
Document only variables that actually enter the analysis.
The two columns teams find hardest are source and derivation, so here is one filled row. Note that derivation records what you did, in enough detail that someone could redo it from the raw variable alone:
high_trust_news,High trust in news from social media,factor,"Low; High","NA if the respondent did not answer the trust item",NEWS_TRUST_W163,"Collapsed 'a lot' and 'some' to High; 'not much' and 'not at all' to Low"
A variable used exactly as it arrived still gets a row — its derivation simply reads “used as received.”
Note the two extra columns. The codebooks shipped with the course datasets carry five columns, because those files arrived already prepared — someone else did the downloading and recoding. Yours does that work, so source and derivation are what let a reader trace each analytic variable back to the raw Pew variable it came from. The Analytic Codebook Guide explains the difference and shows worked examples of both.
See the Analytic Codebook Guide.
GitHub collaboration expectations
The repository is a record of your team’s work, and it should tell a readable story of how the project developed.
Each team member should:
- clone the shared repository,
- pull before beginning a work session,
- make substantive contributions,
- use meaningful commit messages,
- push completed increments,
- and communicate before editing the same section of a file.
Good commit messages describe a completed change:
Add Pew import and variable recodes
Build age-group comparison figure
Revise measurement limitation
Add Table 1 and missing-data note
Avoid:
stuff
update
final
final2
You are not graded on the number of commits. The history should simply show ongoing, shared development rather than a one-time upload at the deadline.
Never commit:
- downloaded data that your
.gitignoreexcludes, - passwords,
- API keys,
- access tokens,
- or files containing private credentials.
The clean-clone test
Before submission, choose a teammate who was not the primary data-prep person.
This is the best way to check whether the project really stands on its own rather than depending on one person’s laptop or memory.
That person should:
- clone the repository into a new folder,
- read the README,
- obtain the raw data as documented in
documentation/data-provenance.mdand place it in the documented location, - open the
.Rproj, - restart R,
- render the main
.qmd—p1_data_brief.qmdorp2_reproduction.qmd— from beginning to end.
No objects should need to be created manually in the Console. No absolute paths should need editing.
This is the project’s reproducibility test.