@leroysheep / MovieWebApp / commits / 13817db274

stash: add --label-ours, --label-theirs, --label-base for apply

Allow callers of "git stash apply" to pass custom labels for conflict markers instead of the default "Updated upstream" and "Stashed changes". Document the new options and add a test. Signed-off-by: Harald Nordgren <haraldnordgren@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Harald Nordgren committed Apr 28, 2026 at 18:39 UTC 13817db2746d48b6d3cfe68e3bf10a1be67865a9
4 files changed +57 -12
Documentation/git-stash.adoc
+10 -1
index b05c990ecd..50bb89f483 100644 --- a/Documentation/git-stash.adoc +++ b/Documentation/git-stash.adoc @@ -12,7 +12,7 @@ git stash list [<log-options>] git stash show [-u | --include-untracked | --only-untracked] [<diff-options>] [<stash>] git stash drop [-q | --quiet] [<stash>] git stash pop [--index] [-q | --quiet] [<stash>] -git stash apply [--index] [-q | --quiet] [<stash>] +git stash apply [--index] [-q | --quiet] [--label-ours=<label>] [--label-theirs=<label>] [--label-base=<label>] [<stash>] git stash branch <branchname> [<stash>] git stash [push] [-p | --patch] [-S | --staged] [-k | --[no-]keep-index] [-q | --quiet] [-u | --include-untracked] [-a | --all] [(-m | --message) <message>] @@ -195,6 +195,15 @@ the index's ones. However, this can fail, when you have conflicts (which are stored in the index, where you therefore can no longer apply the changes as they were originally). +`--label-ours=<label>`:: +`--label-theirs=<label>`:: +`--label-base=<label>`:: + These options are only valid for the `apply` command. ++ +Use the given labels in conflict markers instead of the default +"Updated upstream", "Stashed changes", and "Stash base". +`--label-base` only has an effect with merge.conflictStyle=diff3. + `-k`:: `--keep-index`:: `--no-keep-index`::
builtin/stash.c
+20 -8
index 0d27b2fb1f..32dbc97b47 100644 --- a/builtin/stash.c +++ b/builtin/stash.c @@ -44,7 +44,7 @@ #define BUILTIN_STASH_POP_USAGE \ N_("git stash pop [--index] [-q | --quiet] [<stash>]") #define BUILTIN_STASH_APPLY_USAGE \ - N_("git stash apply [--index] [-q | --quiet] [<stash>]") + N_("git stash apply [--index] [-q | --quiet] [--label-ours=<label>] [--label-theirs=<label>] [--label-base=<label>] [<stash>]") #define BUILTIN_STASH_BRANCH_USAGE \ N_("git stash branch <branchname> [<stash>]") #define BUILTIN_STASH_STORE_USAGE \ @@ -591,7 +591,9 @@ static void unstage_changes_unless_new(struct object_id *orig_tree) } static int do_apply_stash(const char *prefix, struct stash_info *info, - int index, int quiet) + int index, int quiet, + const char *label_ours, const char *label_theirs, + const char *label_base) { int clean, ret; int has_index = index; @@ -643,9 +645,9 @@ static int do_apply_stash(const char *prefix, struct stash_info *info, init_ui_merge_options(&o, the_repository); - o.branch1 = "Updated upstream"; - o.branch2 = "Stashed changes"; - o.ancestor = "Stash base"; + o.branch1 = label_ours ? label_ours : "Updated upstream"; + o.branch2 = label_theirs ? label_theirs : "Stashed changes"; + o.ancestor = label_base ? label_base : "Stash base"; if (oideq(&info->b_tree, &c_tree)) o.branch1 = "Version stash was based on"; @@ -723,11 +725,18 @@ static int apply_stash(int argc, const char **argv, const char *prefix, int ret = -1; int quiet = 0; int index = use_index; + const char *label_ours = NULL, *label_theirs = NULL, *label_base = NULL; struct stash_info info = STASH_INFO_INIT; struct option options[] = { OPT__QUIET(&quiet, N_("be quiet, only report errors")), OPT_BOOL(0, "index", &index, N_("attempt to recreate the index")), + OPT_STRING(0, "label-ours", &label_ours, N_("label"), + N_("label for the upstream side in conflict markers")), + OPT_STRING(0, "label-theirs", &label_theirs, N_("label"), + N_("label for the stashed side in conflict markers")), + OPT_STRING(0, "label-base", &label_base, N_("label"), + N_("label for the base in diff3 conflict markers")), OPT_END() }; @@ -737,7 +746,8 @@ static int apply_stash(int argc, const char **argv, const char *prefix, if (get_stash_info(&info, argc, argv)) goto cleanup; - ret = do_apply_stash(prefix, &info, index, quiet); + ret = do_apply_stash(prefix, &info, index, quiet, + label_ours, label_theirs, label_base); cleanup: free_stash_info(&info); return ret; @@ -836,7 +846,8 @@ static int pop_stash(int argc, const char **argv, const char *prefix, if (get_stash_info_assert(&info, argc, argv)) goto cleanup; - if ((ret = do_apply_stash(prefix, &info, index, quiet))) + if ((ret = do_apply_stash(prefix, &info, index, quiet, + NULL, NULL, NULL))) printf_ln(_("The stash entry is kept in case " "you need it again.")); else @@ -877,7 +888,8 @@ static int branch_stash(int argc, const char **argv, const char *prefix, strvec_push(&cp.args, oid_to_hex(&info.b_commit)); ret = run_command(&cp); if (!ret) - ret = do_apply_stash(prefix, &info, 1, 0); + ret = do_apply_stash(prefix, &info, 1, 0, + NULL, NULL, NULL); if (!ret && info.is_stash_ref) ret = do_drop_stash(&info, 0);
t/t3903-stash.sh
+24
index 70879941c2..bdaad22e1f 100755 --- a/t/t3903-stash.sh +++ b/t/t3903-stash.sh @@ -56,6 +56,7 @@ setup_stash() { git add other-file && test_tick && git commit -m initial && + git tag initial && echo 2 >file && git add file && echo 3 >file && @@ -1790,4 +1791,27 @@ test_expect_success 'stash.index=false overridden by --index' ' test_cmp expect file ' +test_expect_success 'apply with custom conflict labels' ' + git reset --hard initial && + test_commit label-base conflict-file base-content && + echo stashed >conflict-file && + git stash push -m "stashed" && + test_commit label-upstream conflict-file upstream-content && + test_must_fail git -c merge.conflictStyle=diff3 stash apply --label-ours=UP --label-theirs=STASH && + test_grep "^<<<<<<< UP" conflict-file && + test_grep "^||||||| Stash base" conflict-file && + test_grep "^>>>>>>> STASH" conflict-file +' + +test_expect_success 'apply with empty conflict labels' ' + git reset --hard initial && + test_commit empty-label-base conflict-file base-content && + echo stashed >conflict-file && + git stash push -m "stashed" && + test_commit empty-label-upstream conflict-file upstream-content && + test_must_fail git stash apply --label-ours= --label-theirs= && + test_grep "^<<<<<<<$" conflict-file && + test_grep "^>>>>>>>$" conflict-file +' + test_done
xdiff/xmerge.c
+3 -3
index 29dad98c49..659ad4ec97 100644 --- a/xdiff/xmerge.c +++ b/xdiff/xmerge.c @@ -199,9 +199,9 @@ static int fill_conflict_hunk(xdfenv_t *xe1, const char *name1, int size, int i, int style, xdmerge_t *m, char *dest, int marker_size) { - int marker1_size = (name1 ? strlen(name1) + 1 : 0); - int marker2_size = (name2 ? strlen(name2) + 1 : 0); - int marker3_size = (name3 ? strlen(name3) + 1 : 0); + int marker1_size = (name1 && *name1 ? strlen(name1) + 1 : 0); + int marker2_size = (name2 && *name2 ? strlen(name2) + 1 : 0); + int marker3_size = (name3 && *name3 ? strlen(name3) + 1 : 0); int needs_cr = is_cr_needed(xe1, xe2, m); if (marker_size <= 0)