Senseful
Senseful

Reputation: 91891

How to create a git patch with the parent SHA so it can serve as an archive?

Imagine I'm working on an exploratory branch on a git repo and it only has one commit. I decide that my work is not needed any time soon, and I don't want to create a branch/tag. In fact, I'd like to throw away the changes, but just in case I ever need them again, I'd like to save a patch.

For purposes of this post, imagine I only have one change that I want to archive:

* 040cc7c   (HEAD, ExperimentalBranch) This is where the experiment is
* a29ceb7   (master) This is the main branch
...

My proposed archive solution is as follows:

  1. Create a patch of commit 040cc7c.
  2. Archive the patch file somewhere for longterm storage.
  3. Delete the ExperimentalBranch from the repo.

So far everything seems great, until years later when I might want to restore the patch. It will likely reference files/lines that are incompatible and not be able to be applied. To solve this, I could check out the patch's parent SHA and apply it there.

Therefore my proposed unarchive solution is as follows:

  1. Checkout SHA a29ceb7.
  2. Apply the patch.

The only problem is that when I create the patch, I see that it contains SHA 040cc7c, but does not mention a29ceb7 anywhere. It could be very hard for me to figure out the parent of 040cc7c years after I created the patch. Furthermore, because I deleted the branch years earlier, I wouldn't expect there to be a git command that could help me discover the parent.

When creating a patch, is there a way to ensure that its parent SHA is included in the file as well?


My current workaround is to rename the patch to include the parent's SHA, but this can be easy to forget, and is more manual.

Upvotes: 2

Views: 160

Answers (2)

Andy
Andy

Reputation: 4866

I wouldn't really recommend this as an archival strategy, but here's a way of creating an archive repo that stores a particular commit, without storing all of the other commits it is based on.

  1. Create a minimal clone containing the base of the patch:

    git clone --bare --depth 2 --filter=tree:0 -b patch-branch <url of repo with patch> archive-repo
    

    This clone is both shallow (-depth) and partial (—filter). Disclaimer: I'm not sure whether these options are intended to be used together. The depth of the clone should be one more than the number of patch commits (we want the clone to include the patch commits and the base of the patches).

    This has to be done with a real remote protocol, not a file: URL or local path. And the remote needs to support filtering.

  2. Render the patch commit to populate the partial clone with the trees and blobs referenced by the patch:

    cd archive-repo
    git show patch-branch > /dev/null
    

    If you have multiple commits on the patch branch, repeat this for each of them.

  3. (Optional) Pack the archive repository with git repack -ad.

  4. Store the archive repo as a tarball or however you prefer.

To restore, combine the archive repo with a repository containing the base of the patch. In my experiment, fetching or cloning from the archive as a local repo triggered population of additional objects into the partial clone. It probably wouldn’t with a git build that included commit 7b70e9ef. Pushing from the archive to a different repo seems to work.

Upvotes: 0

OznOg
OznOg

Reputation: 4732

I would suggest not to delete the branch, but if you really want to store the patch somewhere else, you may do

git format-patch --base HEAD^ HEAD^

so that the parent (base) is written in the patch

example:

$ git format-patch --base HEAD^ HEAD^ 
0001-test.patch
$ cat 0001-test.patch 
From 057ff8fa3ba485abeb69156e9717570ad483d52c Mon Sep 17 00:00:00 2001
From: Dispeakable me <[email protected]>
Date: Sat, 27 Mar 2021 09:47:23 +0100
Subject: [PATCH] test

---
 test.cpp | 1 +
 1 file changed, 1 insertion(+)

diff --git a/test.cpp b/test.cpp
index 6f4ed1e..1ef4295 100644
--- a/test.cpp
+++ b/test.cpp
@@ -1,4 +1,5 @@
 
+
 #include <list>
 
 class Semaphore {

base-commit: b50a780230e2f3f2be8bf6ad3797de272cafba5c
-- 
2.26.3

and you can check the parent sha1:

$ git cat-file -p  HEAD
tree 5c03e768250fe7fe94d8ba0454feae422abd6aac
parent b50a780230e2f3f2be8bf6ad3797de272cafba5c
author Dispeakable me <[email protected]> 1616834843 +0100
committer Dispeakable me <[email protected]> 1616834843 +0100

test

Upvotes: 2

Related Questions