DigitalForensics

70 13 63 23

Git‑historik i projekttvister: hvem leverede hvad og hvornår

Git-historik i projekttvister: hvem leverede hvad og hvornår

Forside · Gennemgået oktober 2026 · Af John Nielsen

Når et IT-projekt ender i en tvist, stilles to spørgsmål til kildekoden igen og igen: hvem skrev den, og hvornår var den en del af leverancen? Git-historikken kan besvare begge med stor præcision, men kun hvis analysen tager højde for, hvordan arbejdet faktisk er flettet ind: via grene, pull requests, squash, rebase og automatiske formateringer. Et simpelt optal af commits pr. navn er sjældent et godt svar.

Artiklen bygger på kildekode og Git som bevis, der forklarer commit-felterne, signering, reflog og force push. Her handler det om analysen af bidrag og leveringstidspunkter i et projekt med flere parter.

Spørgsmålene skal være præcise

“Hvem leverede hvad” dækker typisk over et af disse spørgsmål:

  • Hvilken part, leverandør, underleverandør eller kundens egne udviklere, har skrevet den kode, der findes i en bestemt version?
  • Hvornår kom en bestemt funktion ind i den gren, der blev leveret?
  • Hvad var ændret mellem to leverancer?
  • Har en ny leverandør overtaget og videreført kode fra den forrige?

Hvert spørgsmål kræver sin egen fremgangsmåde, og rapporten bør angive, hvilket spørgsmål en given opgørelse besvarer. Det er også en fordel at aftale spørgsmålene med begge parter, før analysen begynder, så den ikke senere kan afvises som skræddersyet til ét resultat.

Leverancen: hovedgren og tags

Den leverede kode er normalt en bestemt gren eller et tag. Udgivelser markeres ofte med tags, og et annoteret tag har sit eget tidspunkt og en tagger. Et letvægtstag er kun en pegepind uden egne metadata. Tags kan flyttes eller slettes, så de bør holdes op mod platformens udgivelseshistorik og mod leverancesedler eller mails, der nævner et commit-id.

Hvornår en ændring kom ind i leverancen, er ikke det samme som, hvornår den blev skrevet. Med git log --first-parent på den leverede gren vises de commits, grenen selv har fået, typisk merge-commits fra pull requests. Merge-tidspunktet er det tidspunkt, ændringen blev en del af grenen. En commit med author date i marts kan være flettet ind i juni.

Linje for linje: blame

git blame viser for hver linje i en fil, hvilken commit der senest ændrede den. Det er udgangspunktet for at opgøre, hvem der har skrevet den kode, der findes i en bestemt version. Men blame skal bruges med de rigtige indstillinger:

  • Whitespace og formatering. En commit, der kun ændrede indrykning eller kørte en automatisk formatering, overtager ellers linjerne. Med -w ignoreres whitespace, og med --ignore-revs-file kan rene formateringscommits udelades.
  • Flyttet og kopieret kode. Med -M registreres linjer, der er flyttet inden for en fil, og med -C linjer, der er flyttet eller kopieret fra andre filer. Gentages -C, søges bredere. Uden disse ser en omstrukturering ud som ny kode.
  • Omdøbte filer. Blame følger hele filer, der er omdøbt. For historik pr. fil i git log kræves --follow.

Hvilke commits der er udeladt, og hvorfor, skal fremgå af rapporten. Ellers kan valget i sig selv påvirke resultatet.

Identiteter

Samme person optræder ofte under flere navne og mailadresser: arbejdsmail, privat mail, en adresse fra platformen og et navn stavet på forskellige måder. Git understøtter en .mailmap-fil, der samler identiteter til én, og git shortlog -sne viser antal commits pr. samlet identitet. I en tvist skal koblingen mellem identiteter og personer, og mellem personer og parter, dokumenteres for sig, fx med udviklerlister, kontrakter med underleverandører og platformens brugerkonti. Navnet i en commit er sat i udviklerens egen opsætning og er ikke i sig selv et bevis for, hvem der skrev koden.

Squash, rebase og platformens merges

Måden, pull requests flettes på, ændrer historikken:

  • Squash samler alle commits i en pull request til én. Den enkelte udviklers commits findes da kun i pull requesten på platformen, hvis grenen er slettet. Er flere udviklere involveret, kan bidragene være samlet under ét navn.
  • Rebase skriver commits om med ny committer date. Author date bevares typisk.
  • Merges via platformen kan have platformens egen identitet i committer-feltet.

Platformens data om pull requests, reviews og godkendelser er derfor en nødvendig del af sikringen, se auditlogs på kodeplatformene.

Kode, der ikke er skrevet i projektet

En stor del af et repository er ofte ikke skrevet af nogen af parterne:

  • tredjepartsbiblioteker lagt direkte ind i repositoriet
  • genereret kode fra værktøjer og rammeværk
  • skabeloner og eksempelkode fra rammeværkets leverandør
  • kode fra et tidligere projekt eller en tidligere leverandør

Disse dele bør identificeres og holdes ude af opgørelsen eller opgøres for sig. En SBOM eller pakkefiler kan hjælpe med at udskille afhængigheder, se SBOM og byggeartefakter. Kode foreslået af AI-assistenter giver sine egne spørgsmål, se AI-kodeassistenter i kildekodetvister.

Mål for bidrag

Antal commits, antal ændrede linjer og antal linjer i den nuværende version er tre forskellige mål, og ingen af dem måler værdi eller arbejdsindsats:

  • Commits afhænger af den enkelte udviklers vaner. Nogle laver mange små, andre få store.
  • Ændrede linjer tæller både tilføjelser og sletninger og påvirkes af genereret kode.
  • Linjer i den nuværende version, opgjort med blame, viser hvem der har skrevet det, der står nu, ikke hvem der lavede arbejdet undervejs.

En opgørelse bør derfor angive flere mål og forklare forskellene. Sammenhæng med timer og faktura er en særskilt analyse, se timeregistrering mod commits og tickets.

Sikring før analysen

Analysen skal udføres på en sikret kopi: et bundle eller en mirror-kopi af repositoriet med alle grene og tags, hashet og registreret, og en eksport af platformens pull requests, reviews og udgivelser. Er tidspunktet for leverancen vigtigt, bør tilstanden på overdragelsestidspunktet være sikret særskilt, se leverancens tilstand på overdragelsestidspunktet.

Typiske fejl i fortolkningen

  • Author date bruges som leveringstidspunkt i stedet for tidspunktet for indfletning i den leverede gren.
  • Commits tælles på tværs af alle grene, også grene, der aldrig blev leveret.
  • Formateringscommits og flyttet kode giver forkert ophav i blame.
  • Identiteter samles uden dokumentation for, at de tilhører samme person.
  • Tredjepartskode tælles med som en parts bidrag.

Hvad historikken kan og ikke kan bevise

Git-historikken kan vise, hvilken kode der fandtes i en bestemt version, hvornår den blev flettet ind, og hvilken identitet der er registreret som forfatter. Med platformens data kan den vise, hvem der godkendte og flettede. Den kan ikke alene vise, hvem der fysisk skrev koden, eller hvor meget arbejde den repræsenterer. Tvister mellem stiftere om bidrag til en kodebase er beskrevet fra den juridiske side på digital-bevissikring.dk.

Kilder og versioner

Senest gennemgået: oktober 2026.

Næste skridt

Læs også: Jira, Azure DevOps og backlog-data: sikring og analyse · CI/CD-logs og deployment-historik som bevis

→ Uvildig IT-sagkyndig med forensic-baggrund · For IT-afdelingen · Tlf. 70 13 63 23 · Digital bevissikring hos Nielco IT

Skrevet af John Nielsen, IT‑sagkyndig og indehaver af Nielco IT. Selvstændig siden 2009 og mere end 30 års erfaring med IT‑sikkerhed. Har været IT‑sagkyndig i danske retskredse og ved Den Fælles Europæiske Patentdomstol (UPC). Om John Nielsen · LinkedIn · Redaktionel politik

John Nielsen, IT-sagkyndig

Brug for en forensisk undersøgelse?

Skriv kort, hvilke systemer eller enheder det drejer sig om, og om noget haster, så vender jeg tilbage. Kun civile sager.

Tak for din henvendelse. Jeg vender tilbage hurtigst muligt.