Based on Copying commits between unrelated repositories.
a.sh
:
set -eux
rm -rf a b
show_state() {
echo {{{
git --no-pager log --oneline --graph --all
set +x
git_log `git rev-parse HEAD`
# (cd .git/objects && fd -t f)
for h in `cd .git/objects && fd -t f -E info -E pack | tr -d /.`; do
echo -- $h
git cat-file -p "$h"
done
set -x
if [ -e .git/objects/pack/pack-*.idx ]; then
git verify-pack -v .git/objects/pack/pack-*.idx
fi
echo }}}
}
git_log() {
local commit=$1
while [ "$commit" ]; do
head=$(git cat-file -p `git rev-parse "$commit"` | head -2)
tree=`echo "$head" | egrep '^tree ' | awk '{print $2}'`
parent=`echo "$head" | egrep '^parent ' | awk '{print $2}'`
echo "commit: $commit"
echo " tree: $tree"
if [ "$parent" ]; then
echo " parent: $parent"
fi
git cat-file -p "$tree" | sed -r 's/^/ /'
commit=$parent
done
}
mkdir a
(cd a
git init
echo '1
2
3' > a
git add a
git commit -m 1,2,3
sed -Ei 's/3/33/' a
git add a
git commit -m '3 -> 33'
git format-patch -1 HEAD)
mkdir b
(cd b
git init
echo '11
2
3' > a
git add a
git commit -m 11,2,3
set +x
index=`egrep '^index ' ../a/0001-3-33.patch`
before=`echo "$index" | sed -r 's/index (\w+)\.\.(\w+).*/\1/'`
echo "before: $before"
after=`echo "$index" | sed -r 's/index (\w+)\.\.(\w+).*/\2/'`
echo "after: $after"
set -x
(cd ../a
git cat-file blob "$before") | git hash-object -w --stdin
# git remote add a ../a
# git fetch a
cat a
cat ../a/0001-3-33.patch
# show_state
git --no-pager log --oneline --graph --all
git am -3 "$@" ../a/0001-3-33.patch
# show_state
git --no-pager log --oneline --graph --all
# git remote rm a
git gc --prune=now
# show_state
)
$ sh a.sh
+ rm -rf a b
+ mkdir a
+ cd a
+ git init
hint: Using 'master' as the name for the initial branch. This default branch name
hint: is subject to change. To configure the initial branch name to use in all
hint: of your new repositories, which will suppress this warning, call:
hint:
hint: git config --global init.defaultBranch <name>
hint:
hint: Names commonly chosen instead of 'master' are 'main', 'trunk' and
hint: 'development'. The just-created branch can be renamed via this command:
hint:
hint: git branch -m <name>
Initialized empty Git repository in /tmp/tmp.TDsaH0agCe/a/.git/
+ echo '1
2
3'
+ git add a
+ git commit -m 1,2,3
[master (root-commit) 0ad0231] 1,2,3
1 file changed, 3 insertions(+)
create mode 100644 a
+ sed -Ei s/3/33/ a
+ git add a
+ git commit -m '3 -> 33'
[master 02ab69b] 3 -> 33
1 file changed, 1 insertion(+), 1 deletion(-)
+ git format-patch -1 HEAD
0001-3-33.patch
+ mkdir b
+ cd b
+ git init
hint: Using 'master' as the name for the initial branch. This default branch name
hint: is subject to change. To configure the initial branch name to use in all
hint: of your new repositories, which will suppress this warning, call:
hint:
hint: git config --global init.defaultBranch <name>
hint:
hint: Names commonly chosen instead of 'master' are 'main', 'trunk' and
hint: 'development'. The just-created branch can be renamed via this command:
hint:
hint: git branch -m <name>
Initialized empty Git repository in /tmp/tmp.TDsaH0agCe/b/.git/
+ echo '11
2
3'
+ git add a
+ git commit -m 11,2,3
[master (root-commit) f90c888] 11,2,3
1 file changed, 3 insertions(+)
create mode 100644 a
+ set +x
before: 01e79c3
after: ce5ad9f
+ cd ../a
+ git cat-file blob 01e79c3
+ git hash-object -w --stdin
01e79c32a8c99c557f0757da7cb6d65b3414466d
+ cat a
11
2
3
+ cat ../a/0001-3-33.patch
From 02ab69b168dcb2adbf73e05ac4e36c02f23a85fb Mon Sep 17 00:00:00 2001
From: Yuri Kanivetsky <yuri.kanivetsky@gmail.com>
Date: Sat, 16 Jul 2022 19:29:16 +0300
Subject: [PATCH] 3 -> 33
---
a | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/a b/a
index 01e79c3..ce5ad9f 100644
--- a/a
+++ b/a
@@ -1,3 +1,3 @@
1
2
-3
+33
--
2.36.1
+ git --no-pager log --oneline --graph --all
* f90c888 11,2,3
+ git am -3 ../a/0001-3-33.patch
Applying: 3 -> 33
Using index info to reconstruct a base tree...
M a
Falling back to patching base and 3-way merge...
Auto-merging a
+ git --no-pager log --oneline --graph --all
* 1792554 3 -> 33
* f90c888 11,2,3
+ git gc --prune=now