From: Johannes Sixt <j6t@kdbg.org>
To: Git Mailing List <git@vger.kernel.org>
Subject: [PATCH/RFC] git-post: the opposite of git-cherry-pick
Date: Thu, 5 Oct 2017 21:13:29 +0200 [thread overview]
Message-ID: <c6b52120-98bf-d685-6dc0-3c83e9e80d30@kdbg.org> (raw)
Add a new command that can be used to copy an arbitrary commit
to a branch that is not checked out.
Signed-off-by: Johannes Sixt <j6t@kdbg.org>
---
I have been using this command since years, but got around to
write a man page and tests only now. I hope the man page makes
sense. I don't have the tool chain to build it, though, so
any hints for improvement are welcome.
.gitignore | 1 +
Documentation/git-cherry-pick.txt | 3 +-
Documentation/git-post.txt | 57 +++++++++++++++++++++++++++++
Makefile | 1 +
command-list.txt | 1 +
git-post.sh | 60 ++++++++++++++++++++++++++++++
t/t3514-post.sh | 77 +++++++++++++++++++++++++++++++++++++++
7 files changed, 199 insertions(+), 1 deletion(-)
create mode 100644 Documentation/git-post.txt
create mode 100755 git-post.sh
create mode 100755 t/t3514-post.sh
diff --git a/.gitignore b/.gitignore
index 833ef3b0b7..a16263249a 100644
--- a/.gitignore
+++ b/.gitignore
@@ -106,6 +106,7 @@
/git-pack-refs
/git-parse-remote
/git-patch-id
+/git-post
/git-prune
/git-prune-packed
/git-pull
diff --git a/Documentation/git-cherry-pick.txt b/Documentation/git-cherry-pick.txt
index d35d771fc8..6b34f4d994 100644
--- a/Documentation/git-cherry-pick.txt
+++ b/Documentation/git-cherry-pick.txt
@@ -226,7 +226,8 @@ context lines.
SEE ALSO
--------
-linkgit:git-revert[1]
+linkgit:git-revert[1],
+linkgit:git-post[1]
GIT
---
diff --git a/Documentation/git-post.txt b/Documentation/git-post.txt
new file mode 100644
index 0000000000..e835e62be3
--- /dev/null
+++ b/Documentation/git-post.txt
@@ -0,0 +1,57 @@
+git-post(1)
+===========
+
+NAME
+----
+git-post - Apply a commit on top of a branch that is not checked out
+
+SYNOPSIS
+--------
+[verse]
+'git post' dest-branch [source-rev]
+
+DESCRIPTION
+-----------
+
+Applies the changes made by 'source-rev' (or, if not given, `HEAD`)
+on top of the branch 'dest-branch' and records a new commit.
+'dest-branch' is advanced to point to the new commit.
+The operation that this command performs can be regarded as
+the opposite of cherry-picking.
+
+EXAMPLES
+--------
+
+Assume, while working on a topic, you find and fix an unrelated bug.
+Now:
+
+------------
+$ git commit <1>
+$ git post master <2>
+$ git show | git apply -R && git reset HEAD^ <3>
+------------
+
+<1> create a commit with the fix on the current branch
+<2> copy the fix onto the branch where it ought to be
+<3> revert current topic branch to the unfixed state;
+can also be done with `git reset --keep HEAD^` if there are no
+unstaged changes in files that are modified by the fix
+
+Oftentimes, switching branches triggers a rebuild of a code base.
+With the sequence above the branch switch can be avoided.
+That said, it is good practice to test the bug fix on the
+destination branch eventually.
+
+BUGS
+----
+
+The change can be applied on `dest-branch` only if there is
+no textual conflict.
+
+SEE ALSO
+--------
+linkgit:git-cherry-pick[1].
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Makefile b/Makefile
index b143e4eea3..1753bf176f 100644
--- a/Makefile
+++ b/Makefile
@@ -551,6 +551,7 @@ SCRIPT_SH += git-merge-octopus.sh
SCRIPT_SH += git-merge-one-file.sh
SCRIPT_SH += git-merge-resolve.sh
SCRIPT_SH += git-mergetool.sh
+SCRIPT_SH += git-post.sh
SCRIPT_SH += git-quiltimport.sh
SCRIPT_SH += git-rebase.sh
SCRIPT_SH += git-remote-testgit.sh
diff --git a/command-list.txt b/command-list.txt
index a1fad28fd8..bc95b424d0 100644
--- a/command-list.txt
+++ b/command-list.txt
@@ -98,6 +98,7 @@ git-pack-redundant plumbinginterrogators
git-pack-refs ancillarymanipulators
git-parse-remote synchelpers
git-patch-id purehelpers
+git-post mainporcelain
git-prune ancillarymanipulators
git-prune-packed plumbingmanipulators
git-pull mainporcelain remote
diff --git a/git-post.sh b/git-post.sh
new file mode 100755
index 0000000000..6627d69f73
--- /dev/null
+++ b/git-post.sh
@@ -0,0 +1,60 @@
+#!/bin/sh
+# Copyright (c) 2017 Johannes Sixt
+
+SUBDIRECTORY_OK=Yes
+OPTIONS_SPEC="\
+git post dest-branch [source-rev]
+--
+"
+. git-sh-setup
+
+while test $# != 0
+do
+ case "$1" in
+ --) shift; break;;
+ -*) usage;;
+ *) break;;
+ esac
+ shift
+done
+
+dest=$(git rev-parse --verify --symbolic-full-name "$1") || exit
+if test -z "$dest"
+then
+ die "$(gettext "Destination must be a branch tip")"
+fi
+
+shift
+case $# in
+0) set -- HEAD;;
+1) : good;;
+*) usage;;
+esac
+
+# apply change to a temporary index
+tmpidx=$GIT_DIR/index-post-$$
+git read-tree --index-output="$tmpidx" "$dest" || exit
+GIT_INDEX_FILE=$tmpidx
+export GIT_INDEX_FILE
+trap 'rm -f "$tmpidx"' 0 1 2 15
+
+git diff-tree -p --binary -M -C "$1" | git apply --cached || exit
+
+newtree=$(git write-tree) &&
+newrev=$(
+ eval "$(get_author_ident_from_commit "$1")" &&
+ export GIT_AUTHOR_NAME GIT_AUTHOR_EMAIL GIT_AUTHOR_DATE
+ git-cat-file commit "$1" | sed -e '1,/^$/d' |
+ git commit-tree $newtree -p "$dest"
+) || exit
+
+if git check-ref-format "$dest"
+then
+ set_reflog_action post
+ subject=$(git log --no-walk --pretty=%s "$newrev") &&
+ git update-ref -m "$GIT_REFLOG_ACTION: $subject" "$dest" "$newrev" || exit
+fi
+if test -z "$GIT_QUIET"
+then
+ git rev-list -1 --oneline "$newrev"
+fi
diff --git a/t/t3514-post.sh b/t/t3514-post.sh
new file mode 100755
index 0000000000..4d31515c52
--- /dev/null
+++ b/t/t3514-post.sh
@@ -0,0 +1,77 @@
+#!/bin/sh
+
+test_description='test git post
+
+We build this history:
+
+ A--B--C <-- master, HEAD
+ /
+ O <-- side-base, side
+
+Then we post B and C on top of branch "side":
+
+ A--B--C <-- master, HEAD
+ /
+ O <-- side-base
+ \
+ B*--C* <-- side
+
+B has a different author, which must be copied to B*.
+'
+
+. ./test-lib.sh
+
+test_expect_success setup '
+
+ printf "a%s\n" 1 2 3 4 >file-a &&
+ printf "b%s\n" 5 6 7 8 >file-b &&
+
+ test_tick &&
+ git add file-a file-b &&
+ git commit -m initial &&
+ git tag side-base &&
+
+ test_tick &&
+ echo "Advance master" >>file-a &&
+ git commit -a -m advance-master &&
+
+ test_tick &&
+ echo "Unrelated fix" >>file-b &&
+ GIT_AUTHOR_NAME="S O Else" git commit -a -m fix-for-b &&
+
+ test_tick &&
+ echo "Another fix" >>file-b &&
+ git commit -a -m another-fix-for-b
+'
+
+test_expect_success 'post two commits on top of side' '
+
+ git branch -f side side-base &&
+ test_tick &&
+ git post side HEAD^ &&
+ test_tick &&
+ git post side &&
+
+ git log --pretty="%at %an %ae %s" HEAD~2.. >expect &&
+ git log --pretty="%at %an %ae %s" side-base..side >actual &&
+
+ test_cmp expect actual &&
+ git cat-file blob side:file-b >actual &&
+ test_cmp file-b actual &&
+
+ git diff --exit-code side-base side -- file-a # no change
+'
+
+test_expect_success 'post requiring merge resolution fails' '
+
+ git branch -f side side-base &&
+ test_must_fail git post side HEAD
+'
+
+test_expect_success 'cannot post onto arbitrary commit name' '
+
+ git branch -f side side-base &&
+ test_must_fail git post side^0 HEAD^
+'
+
+test_done
--
2.14.2.808.g3bc32f2729
next reply other threads:[~2017-10-05 19:13 UTC|newest]
Thread overview: 8+ messages / expand[flat|nested] mbox.gz Atom feed top
2017-10-05 19:13 Johannes Sixt [this message]
2017-10-05 19:33 ` [PATCH/RFC] git-post: the opposite of git-cherry-pick Stefan Beller
2017-10-05 21:22 ` Johannes Sixt
2017-10-13 10:51 ` Ævar Arnfjörð Bjarmason
2017-10-15 15:09 ` Johannes Sixt
2017-10-16 23:01 ` Rafael Ascensao
2017-10-17 17:30 ` Johannes Sixt
2017-10-17 21:15 ` Igor Djordjevic
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
List information: http://vger.kernel.org/majordomo-info.html
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=c6b52120-98bf-d685-6dc0-3c83e9e80d30@kdbg.org \
--to=j6t@kdbg.org \
--cc=git@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
Code repositories for project(s) associated with this public inbox
https://80x24.org/mirrors/git.git
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).